diff --git a/course/externallib.php b/course/externallib.php index ac64324eb4b..1f631b27a3b 100644 --- a/course/externallib.php +++ b/course/externallib.php @@ -611,6 +611,7 @@ class core_course_external extends external_api { $courseinfo['customfields'][] = [ 'type' => $data->get_type(), 'value' => $data->get_value(), + 'valueraw' => $data->get_data_controller()->get_value(), 'name' => $data->get_name(), 'shortname' => $data->get_shortname() ]; @@ -735,6 +736,7 @@ class core_course_external extends external_api { 'shortname' => new external_value(PARAM_ALPHANUMEXT, 'The shortname of the custom field'), 'type' => new external_value(PARAM_COMPONENT, 'The type of the custom field - text, checkbox...'), + 'valueraw' => new external_value(PARAM_RAW, 'The raw value of the custom field'), 'value' => new external_value(PARAM_RAW, 'The value of the custom field')] ), 'Custom fields and associated values', VALUE_OPTIONAL), ), 'course' @@ -2489,6 +2491,7 @@ class core_course_external extends external_api { $coursereturns['customfields'][] = [ 'type' => $data->get_type(), 'value' => $data->get_value(), + 'valueraw' => $data->get_data_controller()->get_value(), 'name' => $data->get_name(), 'shortname' => $data->get_shortname() ]; @@ -2640,6 +2643,7 @@ class core_course_external extends external_api { 'The shortname of the custom field - to be able to build the field class in the code'), 'type' => new external_value(PARAM_ALPHANUMEXT, 'The type of the custom field - text field, checkbox...'), + 'valueraw' => new external_value(PARAM_RAW, 'The raw value of the custom field'), 'value' => new external_value(PARAM_RAW, 'The value of the custom field'), ) ), 'Custom fields', VALUE_OPTIONAL), diff --git a/course/tests/externallib_test.php b/course/tests/externallib_test.php index fcf938bc876..dcd48ee7cb6 100644 --- a/course/tests/externallib_test.php +++ b/course/tests/externallib_test.php @@ -775,8 +775,16 @@ class core_course_externallib_testcase extends externallib_advanced_testcase { array('name' => 'coursedisplay', 'value' => $dbcourse->coursedisplay), )); } - if ($dbcourse->id == 4) { - $this->assertEquals($course['customfields'], [array_merge($customfield, $customfieldvalue)]); + + // Assert custom field that we previously added to test course 4. + if ($dbcourse->id == $course4->id) { + $this->assertEquals([ + 'shortname' => $customfield['shortname'], + 'name' => $customfield['name'], + 'type' => $customfield['type'], + 'value' => $customfieldvalue['value'], + 'valueraw' => $customfieldvalue['value'], + ], $course['customfields'][0]); } } @@ -789,6 +797,49 @@ class core_course_externallib_testcase extends externallib_advanced_testcase { $this->assertEquals($DB->count_records('course'), count($courses)); } + /** + * Test retrieving courses returns custom field data + */ + public function test_get_courses_customfields(): void { + $this->resetAfterTest(); + $this->setAdminUser(); + + $fieldcategory = $this->getDataGenerator()->create_custom_field_category([]); + $datefield = $this->getDataGenerator()->create_custom_field([ + 'categoryid' => $fieldcategory->get('id'), + 'shortname' => 'mydate', + 'name' => 'My date', + 'type' => 'date', + ]); + + $newcourse = $this->getDataGenerator()->create_course(['customfields' => [ + [ + 'shortname' => $datefield->get('shortname'), + 'value' => 1580389200, // 30/01/2020 13:00 GMT. + ], + ]]); + + $courses = external_api::clean_returnvalue( + core_course_external::get_courses_returns(), + core_course_external::get_courses(['ids' => [$newcourse->id]]) + ); + + $this->assertCount(1, $courses); + $course = reset($courses); + + $this->assertArrayHasKey('customfields', $course); + $this->assertCount(1, $course['customfields']); + + // Assert the received custom field, "value" containing a human-readable version and "valueraw" the unmodified version. + $this->assertEquals([ + 'name' => $datefield->get('name'), + 'shortname' => $datefield->get('shortname'), + 'type' => $datefield->get('type'), + 'value' => userdate(1580389200), + 'valueraw' => 1580389200, + ], reset($course['customfields'])); + } + /** * Test get_courses without capability */ @@ -912,6 +963,49 @@ class core_course_externallib_testcase extends externallib_advanced_testcase { $results = core_course_external::search_courses('blocklist', $blockid); } + /** + * Test searching for courses returns custom field data + */ + public function test_search_courses_customfields(): void { + $this->resetAfterTest(); + $this->setAdminUser(); + + $fieldcategory = $this->getDataGenerator()->create_custom_field_category([]); + $datefield = $this->getDataGenerator()->create_custom_field([ + 'categoryid' => $fieldcategory->get('id'), + 'shortname' => 'mydate', + 'name' => 'My date', + 'type' => 'date', + ]); + + $newcourse = $this->getDataGenerator()->create_course(['customfields' => [ + [ + 'shortname' => $datefield->get('shortname'), + 'value' => 1580389200, // 30/01/2020 13:00 GMT. + ], + ]]); + + $result = external_api::clean_returnvalue( + core_course_external::search_courses_returns(), + core_course_external::search_courses('search', $newcourse->shortname) + ); + + $this->assertCount(1, $result['courses']); + $course = reset($result['courses']); + + $this->assertArrayHasKey('customfields', $course); + $this->assertCount(1, $course['customfields']); + + // Assert the received custom field, "value" containing a human-readable version and "valueraw" the unmodified version. + $this->assertEquals([ + 'name' => $datefield->get('name'), + 'shortname' => $datefield->get('shortname'), + 'type' => $datefield->get('type'), + 'value' => userdate(1580389200), + 'valueraw' => 1580389200, + ], reset($course['customfields'])); + } + /** * Create a course with contents * @return array A list with the course object and course modules objects @@ -2453,8 +2547,13 @@ class core_course_externallib_testcase extends externallib_advanced_testcase { $this->assertCount(1, $result['courses']); $this->assertEquals($course2->id, $result['courses'][0]['id']); // Check custom fields properly returned. - unset($customfield['categoryid']); - $this->assertEquals([array_merge($customfield, $customfieldvalue)], $result['courses'][0]['customfields']); + $this->assertEquals([ + 'shortname' => $customfield['shortname'], + 'name' => $customfield['name'], + 'type' => $customfield['type'], + 'value' => $customfieldvalue['value'], + 'valueraw' => $customfieldvalue['value'], + ], $result['courses'][0]['customfields'][0]); $result = core_course_external::get_courses_by_field('ids', "$course1->id,$course2->id"); $result = external_api::clean_returnvalue(core_course_external::get_courses_by_field_returns(), $result); @@ -2583,6 +2682,49 @@ class core_course_externallib_testcase extends externallib_advanced_testcase { $this->assertCount(0, $result['courses']); } + /** + * Test retrieving courses by field returns custom field data + */ + public function test_get_courses_by_field_customfields(): void { + $this->resetAfterTest(); + $this->setAdminUser(); + + $fieldcategory = $this->getDataGenerator()->create_custom_field_category([]); + $datefield = $this->getDataGenerator()->create_custom_field([ + 'categoryid' => $fieldcategory->get('id'), + 'shortname' => 'mydate', + 'name' => 'My date', + 'type' => 'date', + ]); + + $newcourse = $this->getDataGenerator()->create_course(['customfields' => [ + [ + 'shortname' => $datefield->get('shortname'), + 'value' => 1580389200, // 30/01/2020 13:00 GMT. + ], + ]]); + + $result = external_api::clean_returnvalue( + core_course_external::get_courses_by_field_returns(), + core_course_external::get_courses_by_field('id', $newcourse->id) + ); + + $this->assertCount(1, $result['courses']); + $course = reset($result['courses']); + + $this->assertArrayHasKey('customfields', $course); + $this->assertCount(1, $course['customfields']); + + // Assert the received custom field, "value" containing a human-readable version and "valueraw" the unmodified version. + $this->assertEquals([ + 'name' => $datefield->get('name'), + 'shortname' => $datefield->get('shortname'), + 'type' => $datefield->get('type'), + 'value' => userdate(1580389200), + 'valueraw' => 1580389200, + ], reset($course['customfields'])); + } + public function test_get_courses_by_field_invalid_field() { $this->expectException('invalid_parameter_exception'); $result = core_course_external::get_courses_by_field('zyx', 'x'); diff --git a/course/upgrade.txt b/course/upgrade.txt index e56837d5b02..69bf9230ad4 100644 --- a/course/upgrade.txt +++ b/course/upgrade.txt @@ -5,6 +5,8 @@ information provided here is intended especially for developers. * The function make_categories_options() has now been deprecated. Please use \core_course_category::make_categories_list() instead. * External function core_course_external::get_course_contents now returns a new field contextid with the module context id. +* The core_course_external class methods get_courses(), get_courses_by_field() and search_courses() now return a "valueraw" property + for each custom course field, which contains the original/unformatted version of the custom field value. === 3.9 ===