This commit is contained in:
Eloy Lafuente (stronk7)
2020-05-01 01:51:49 +02:00
18 changed files with 630 additions and 18 deletions
+33 -3
View File
@@ -284,6 +284,15 @@ class tool_uploadcourse_course {
return $this->errors;
}
/**
* Return array of valid fields for default values
*
* @return array
*/
protected function get_valid_fields() {
return array_merge(self::$validfields, \tool_uploadcourse_helper::get_custom_course_field_names());
}
/**
* Assemble the course data based on defaults.
*
@@ -293,7 +302,7 @@ class tool_uploadcourse_course {
* @return array
*/
protected function get_final_create_data($data) {
foreach (self::$validfields as $field) {
foreach ($this->get_valid_fields() as $field) {
if (!isset($data[$field]) && isset($this->defaults[$field])) {
$data[$field] = $this->defaults[$field];
}
@@ -316,9 +325,9 @@ class tool_uploadcourse_course {
global $DB;
$newdata = array();
$existingdata = $DB->get_record('course', array('shortname' => $this->shortname));
foreach (self::$validfields as $field) {
foreach ($this->get_valid_fields() as $field) {
if ($missingonly) {
if (!is_null($existingdata->$field) and $existingdata->$field !== '') {
if (isset($existingdata->$field) and $existingdata->$field !== '') {
continue;
}
}
@@ -699,6 +708,27 @@ class tool_uploadcourse_course {
$coursedata[$rolekey] = $rolename;
}
// Custom fields. If the course already exists and mode isn't set to force creation, we can use its context.
if ($exists && $mode !== tool_uploadcourse_processor::MODE_CREATE_ALL) {
$context = context_course::instance($coursedata['id']);
} else {
// The category ID is taken from the defaults if it exists, otherwise from course data.
$context = context_coursecat::instance($this->defaults['category'] ?? $coursedata['category']);
}
$customfielddata = tool_uploadcourse_helper::get_custom_course_field_data($this->rawdata, $this->defaults, $context,
$errors);
if (!empty($errors)) {
foreach ($errors as $key => $message) {
$this->error($key, $message);
}
return false;
}
foreach ($customfielddata as $name => $value) {
$coursedata[$name] = $value;
}
// Some validation.
if (!empty($coursedata['format']) && !in_array($coursedata['format'], tool_uploadcourse_helper::get_course_formats())) {
$this->error('invalidcourseformat', new lang_string('invalidcourseformat', 'tool_uploadcourse'));
+98 -2
View File
@@ -337,6 +337,103 @@ class tool_uploadcourse_helper {
return $rolenames;
}
/**
* Return array of all custom course fields indexed by their shortname
*
* @return \core_customfield\field_controller[]
*/
public static function get_custom_course_fields(): array {
$result = [];
$fields = \core_course\customfield\course_handler::create()->get_fields();
foreach ($fields as $field) {
$result[$field->get('shortname')] = $field;
}
return $result;
}
/**
* Return array of custom field element names
*
* @return string[]
*/
public static function get_custom_course_field_names(): array {
$result = [];
$fields = self::get_custom_course_fields();
foreach ($fields as $field) {
$controller = \core_customfield\data_controller::create(0, null, $field);
$result[] = $controller->get_form_element_name();
}
return $result;
}
/**
* Return any elements from passed $data whose key matches one of the custom course fields defined for the site
*
* @param array $data
* @param array $defaults
* @param context $context
* @param array $errors Will be populated with any errors
* @return array
*/
public static function get_custom_course_field_data(array $data, array $defaults, context $context,
array &$errors = []): array {
$fields = self::get_custom_course_fields();
$result = [];
$canchangelockedfields = guess_if_creator_will_have_course_capability('moodle/course:changelockedcustomfields', $context);
foreach ($data as $name => $originalvalue) {
if (preg_match('/^customfield_(?<name>.*)?$/', $name, $matches)
&& isset($fields[$matches['name']])) {
$fieldname = $matches['name'];
$field = $fields[$fieldname];
// Skip field if it's locked and user doesn't have capability to change locked fields.
if ($field->get_configdata_property('locked') && !$canchangelockedfields) {
continue;
}
// Create field data controller.
$controller = \core_customfield\data_controller::create(0, null, $field);
$controller->set('id', 1);
$defaultvalue = $defaults["customfield_{$fieldname}"] ?? $controller->get_default_value();
$value = (empty($originalvalue) ? $defaultvalue : $field->parse_value($originalvalue));
// If we initially had a value, but now don't, then reset it to the default.
if (!empty($originalvalue) && empty($value)) {
$value = $defaultvalue;
}
// Validate data with controller.
$fieldformdata = [$controller->get_form_element_name() => $value];
$validationerrors = $controller->instance_form_validation($fieldformdata, []);
if (count($validationerrors) > 0) {
$errors['customfieldinvalid'] = new lang_string('customfieldinvalid', 'tool_uploadcourse',
$field->get_formatted_name());
continue;
}
$controller->set($controller->datafield(), $value);
// Pass an empty object to the data controller, which will transform it to a correct name/value pair.
$instance = new stdClass();
$controller->instance_form_before_set_data($instance);
$result = array_merge($result, (array) $instance);
}
}
return $result;
}
/**
* Helper to increment an ID number.
*
@@ -493,5 +590,4 @@ class tool_uploadcourse_helper {
}
return $id;
}
}
}
@@ -173,6 +173,10 @@ class tool_uploadcourse_step2_form extends tool_uploadcourse_base_form {
$mform->addHelpButton('defaults[enablecompletion]', 'enablecompletion', 'completion');
}
// Add custom fields to the form.
$handler = \core_course\customfield\course_handler::create();
$handler->instance_form_definition($mform, 0, 'defaultvaluescustomfieldcategory', 'tool_uploadcourse');
// Hidden fields.
$mform->addElement('hidden', 'importid');
$mform->setType('importid', PARAM_INT);
@@ -182,6 +186,10 @@ class tool_uploadcourse_step2_form extends tool_uploadcourse_base_form {
$this->add_action_buttons(true, get_string('uploadcourses', 'tool_uploadcourse'));
// Prepare custom fields data.
$data = (object) $data;
$handler->instance_form_before_set_data($data);
$this->set_data($data);
}
@@ -219,6 +227,9 @@ class tool_uploadcourse_step2_form extends tool_uploadcourse_base_form {
$enddate = $format->get_default_course_enddate($mform, array('startdate' => 'defaults[startdate]'));
$mform->setDefault('defaults[enddate]', $enddate);
}
// Tweak the form with values provided by custom fields in use.
\core_course\customfield\course_handler::create()->instance_form_definition_after_data($mform);
}
/**
@@ -237,6 +248,9 @@ class tool_uploadcourse_step2_form extends tool_uploadcourse_base_form {
$errors['defaults[enddate]'] = get_string($errorcode, 'error');
}
// Custom fields validation.
array_merge($errors, \core_course\customfield\course_handler::create()->instance_form_validation($data, $files));
return $errors;
}
}
+6
View File
@@ -78,6 +78,12 @@ if ($form2data = $mform2->is_cancelled()) {
$options = (array) $form2data->options;
$defaults = (array) $form2data->defaults;
// Custom field defaults.
$customfields = tool_uploadcourse_helper::get_custom_course_field_names();
foreach ($customfields as $customfield) {
$defaults[$customfield] = $form2data->{$customfield};
}
// Restorefile deserves its own logic because formslib does not really appreciate
// when the name of a filepicker is an array...
$options['restorefile'] = '';
@@ -75,6 +75,7 @@ $string['csvdelimiter_help'] = 'CSV delimiter of the CSV file.';
$string['csvfileerror'] = 'There is something wrong with the format of the CSV file. Please check the number of headings and columns match, and that the delimiter and file encoding are correct: {$a}';
$string['csvline'] = 'Line';
$string['defaultvalues'] = 'Default course values';
$string['defaultvaluescustomfieldcategory'] = 'Default values for \'{$a}\'';
$string['encoding'] = 'Encoding';
$string['encoding_help'] = 'Encoding of the CSV file.';
$string['errorwhilerestoringcourse'] = 'Error while restoring the course';
@@ -102,6 +103,7 @@ $string['mode_help'] = 'This allows you to specify if courses can be created and
$string['nochanges'] = 'No changes';
$string['pluginname'] = 'Course upload';
$string['preview'] = 'Preview';
$string['customfieldinvalid'] = 'Custom field \'{$a}\' is empty or contains invalid data';
$string['reset'] = 'Reset course after upload';
$string['reset_help'] = 'Whether to reset the course after creating/updating it.';
$string['result'] = 'Result';
@@ -42,3 +42,66 @@ Feature: An admin can create courses using a CSV file
And I should see "Course 1"
And I should see "Course 2"
And I should see "Course 3"
@javascript
Scenario: Creation of new courses with custom fields
Given the following "custom field categories" exist:
| name | component | area | itemid |
| Other | core_course | course | 0 |
And the following "custom fields" exist:
| name | category | type | shortname | configdata |
| Field 1 | Other | checkbox | checkbox | |
| Field 2 | Other | date | date | |
| Field 3 | Other | select | select | {"options":"a\nb\nc"} |
| Field 4 | Other | text | text | |
| Field 5 | Other | textarea | textarea | |
When I upload "admin/tool/uploadcourse/tests/fixtures/courses_custom_fields.csv" file to "File" filemanager
And I set the field "Upload mode" to "Create new courses only, skip existing ones"
And I click on "Preview" "button"
And I click on "Upload courses" "button"
Then I should see "Course created"
And I should see "Courses created: 1"
And I am on site homepage
And I should see "Course fields 1"
And I should see "Field 1: Yes"
And I should see "Field 2: Tuesday, 1 October 2019, 2:00"
And I should see "Field 3: b"
And I should see "Field 4: Hello"
And I should see "Field 5: Goodbye"
@javascript
Scenario: Creation of new courses with custom fields using defaults
Given the following "custom field categories" exist:
| name | component | area | itemid |
| Other | core_course | course | 0 |
And the following "custom fields" exist:
| name | category | type | shortname | configdata |
| Field 1 | Other | checkbox | checkbox | {"checkbydefault":1} |
| Field 2 | Other | date | date | {"includetime":0} |
| Field 3 | Other | select | select | {"options":"a\nb\nc","defaultvalue":"b"} |
| Field 4 | Other | text | text | {"defaultvalue":"Hello"} |
| Field 5 | Other | textarea | textarea | {"defaultvalue":"Some text","defaultvalueformat":1} |
When I upload "admin/tool/uploadcourse/tests/fixtures/courses.csv" file to "File" filemanager
And I set the field "Upload mode" to "Create all, increment shortname if needed"
And I click on "Preview" "button"
And I expand all fieldsets
And the field "Field 1" matches value "1"
And the field "Field 3" matches value "b"
And the field "Field 4" matches value "Hello"
And the field "Field 5" matches value "Some text"
# We have to enable the date field manually.
And I set the following fields to these values:
| customfield_date[enabled] | 1 |
| customfield_date[day] | 1 |
| customfield_date[month] | June |
| customfield_date[year] | 2020 |
And I click on "Upload courses" "button"
Then I should see "Course created"
And I should see "Courses created: 3"
And I am on site homepage
And I should see "Course 1"
And I should see "Field 1: Yes"
And I should see "Field 2: 1 June 2020"
And I should see "Field 3: b"
And I should see "Field 4: Hello"
And I should see "Field 5: Some text"
@@ -7,7 +7,8 @@ Feature: An admin can update courses using a CSV file
Background:
Given the following "courses" exist:
| fullname | shortname | category |
| Some random name | C1 | 0 |
| Some random name | C1 | 0 |
| Another course | CF1 | 0 |
And I log in as "admin"
And I navigate to "Courses > Upload courses" in site administration
@@ -28,3 +29,31 @@ Feature: An admin can update courses using a CSV file
And I should see "Course 1"
And I should not see "Course 2"
And I should not see "Course 3"
@javascript
Scenario: Updating a course with custom fields
Given the following "custom field categories" exist:
| name | component | area | itemid |
| Other | core_course | course | 0 |
And the following "custom fields" exist:
| name | category | type | shortname | configdata |
| Field 1 | Other | checkbox | checkbox | |
| Field 2 | Other | date | date | |
| Field 3 | Other | select | select | {"options":"a\nb\nc"} |
| Field 4 | Other | text | text | |
| Field 5 | Other | textarea | textarea | |
When I upload "admin/tool/uploadcourse/tests/fixtures/courses_custom_fields.csv" file to "File" filemanager
And I set the following fields to these values:
| Upload mode | Only update existing courses |
| Update mode | Update with CSV data only |
And I click on "Preview" "button"
And I click on "Upload courses" "button"
Then I should see "Course updated"
And I should see "Courses updated: 1"
And I am on site homepage
And I should see "Course fields 1"
And I should see "Field 1: Yes"
And I should see "Field 2: Tuesday, 1 October 2019, 2:00"
And I should see "Field 3: b"
And I should see "Field 4: Hello"
And I should see "Field 5: Goodbye"
+159 -2
View File
@@ -1081,6 +1081,136 @@ class tool_uploadcourse_course_testcase extends advanced_testcase {
$this->assertEquals(strtotime('12th July 2013'), $enroldata['manual']->enrolenddate);
}
/**
* Test upload processing of course custom fields
*/
public function test_custom_fields_data() {
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course(['shortname' => 'C1']);
// Create our custom fields.
$category = $this->get_customfield_generator()->create_category();
$this->create_custom_field($category, 'date', 'mydatefield');
$this->create_custom_field($category, 'text', 'mytextfield');
$this->create_custom_field($category, 'textarea', 'mytextareafield');
// Perform upload.
$mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
$updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
$dataupload = [
'shortname' => $course->shortname,
'customfield_mydatefield' => '2020-04-01 16:00',
'customfield_mytextfield' => 'Hello',
'customfield_mytextareafield' => 'Is it me you\'re looking for?',
];
$uploader = new tool_uploadcourse_course($mode, $updatemode, $dataupload);
$this->assertTrue($uploader->prepare());
$uploader->proceed();
// Confirm presence of course custom fields.
$data = \core_course\customfield\course_handler::create()->export_instance_data_object($course->id);
$this->assertEquals('Wednesday, 1 April 2020, 4:00 PM', $data->mydatefield);
$this->assertEquals($dataupload['customfield_mytextfield'], $data->mytextfield);
$this->assertContains($dataupload['customfield_mytextareafield'], $data->mytextareafield);
}
/**
* Test upload processing of course custom field that is required but empty
*/
public function test_custom_fields_data_required() {
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course(['shortname' => 'C1']);
// Create our custom field.
$category = $this->get_customfield_generator()->create_category();
$this->create_custom_field($category, 'select', 'myselect', ['required' => true, 'options' => "Cat\nDog"]);
$mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
$updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
$dataupload = [
'shortname' => $course->shortname,
'customfield_myselect' => null,
];
$uploader = new tool_uploadcourse_course($mode, $updatemode, $dataupload);
$this->assertFalse($uploader->prepare());
$this->assertArrayHasKey('customfieldinvalid', $uploader->get_errors());
// Try again with a default value.
$defaults = [
'customfield_myselect' => 2, // Our second option: Dog.
];
$uploader = new tool_uploadcourse_course($mode, $updatemode, $dataupload, $defaults);
$this->assertTrue($uploader->prepare());
$uploader->proceed();
// Confirm presence of course custom fields.
$data = \core_course\customfield\course_handler::create()->export_instance_data_object($course->id);
$this->assertEquals('Dog', $data->myselect);
}
/**
* Test upload processing of course custom field with an invalid select option
*/
public function test_custom_fields_data_invalid_select_option() {
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course(['shortname' => 'C1']);
// Create our custom field.
$category = $this->get_customfield_generator()->create_category();
$this->create_custom_field($category, 'select', 'myselect',
['required' => true, 'options' => "Cat\nDog", 'defaultvalue' => 'Cat']);
$mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
$updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
$dataupload = [
'shortname' => $course->shortname,
'customfield_myselect' => 'Fish', // No, invalid.
];
$uploader = new tool_uploadcourse_course($mode, $updatemode, $dataupload);
$this->assertTrue($uploader->prepare());
$uploader->proceed();
// Confirm presence of course custom fields.
$data = \core_course\customfield\course_handler::create()->export_instance_data_object($course->id);
$this->assertEquals('Cat', $data->myselect);
}
/**
* Test upload processing of course custom field with an out of range date
*/
public function test_custom_fields_data_invalid_date() {
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course(['shortname' => 'C1']);
// Create our custom field.
$category = $this->get_customfield_generator()->create_category();
$this->create_custom_field($category, 'date', 'mydate',
['mindate' => strtotime('2020-04-01'), 'maxdate' => '2020-04-30']);
$mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
$updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
$dataupload = [
'shortname' => $course->shortname,
'customfield_mydate' => '2020-05-06', // Out of range.
];
$uploader = new tool_uploadcourse_course($mode, $updatemode, $dataupload);
$this->assertFalse($uploader->prepare());
$this->assertArrayHasKey('customfieldinvalid', $uploader->get_errors());
}
public function test_idnumber_problems() {
$this->resetAfterTest(true);
@@ -1224,7 +1354,34 @@ class tool_uploadcourse_course_testcase extends advanced_testcase {
$co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
$this->assertFalse($co->prepare());
$this->assertArrayHasKey('cannotrenameshortnamealreadyinuse', $co->get_errors());
}
}
/**
* Get custom field plugin generator
*
* @return core_customfield_generator
*/
protected function get_customfield_generator() : core_customfield_generator {
return $this->getDataGenerator()->get_plugin_generator('core_customfield');
}
/**
* Helper method to create custom course field
*
* @param \core_customfield\category_controller $category
* @param string $type
* @param string $shortname
* @param array $configdata
* @return \core_customfield\field_controller
*/
protected function create_custom_field(\core_customfield\category_controller $category, string $type, string $shortname,
array $configdata = []) : \core_customfield\field_controller {
return $this->get_customfield_generator()->create_field([
'categoryid' => $category->get('id'),
'type' => $type,
'shortname' => $shortname,
'configdata' => $configdata,
]);
}
}
@@ -0,0 +1,2 @@
shortname,fullname,summary,category,customfield_checkbox,customfield_date,customfield_select,customfield_text,customfield_textarea
CF1,Course fields 1,Testing course fields,1,1,2019-10-01 14:00,b,Hello,Goodbye
1 shortname fullname summary category customfield_checkbox customfield_date customfield_select customfield_text customfield_textarea
2 CF1 Course fields 1 Testing course fields 1 1 2019-10-01 14:00 b Hello Goodbye
+105 -1
View File
@@ -250,6 +250,81 @@ class tool_uploadcourse_helper_testcase extends advanced_testcase {
$this->assertArrayHasKey('invalidroles', $errors);
}
/**
* Test custom field data processing
*/
public function test_get_custom_course_field_data() {
global $DB;
$this->resetAfterTest();
// Create all the fields!
$category = $this->get_customfield_generator()->create_category();
$checkboxfield = $this->create_custom_field($category, 'checkbox', 'mycheckbox');
$datefield = $this->create_custom_field($category, 'date', 'mydate');
$selectfield = $this->create_custom_field($category, 'select', 'myselect', ['options' => "Red\nGreen\nBlue"]);
$textfield = $this->create_custom_field($category, 'text', 'mytext', ['locked' => 1]);
$textareafield = $this->create_custom_field($category, 'textarea', 'mytextarea');
$fields = tool_uploadcourse_helper::get_custom_course_fields();
$this->assertCount(5, $fields);
$this->assertArrayHasKey($checkboxfield->get('shortname'), $fields);
$this->assertInstanceOf(customfield_checkbox\field_controller::class, $fields[$checkboxfield->get('shortname')]);
$this->assertArrayHasKey($datefield->get('shortname'), $fields);
$this->assertInstanceOf(customfield_date\field_controller::class, $fields[$datefield->get('shortname')]);
$this->assertArrayHasKey($selectfield->get('shortname'), $fields);
$this->assertInstanceOf(customfield_select\field_controller::class, $fields[$selectfield->get('shortname')]);
$this->assertArrayHasKey($textfield->get('shortname'), $fields);
$this->assertInstanceOf(customfield_text\field_controller::class, $fields[$textfield->get('shortname')]);
$this->assertArrayHasKey($textareafield->get('shortname'), $fields);
$this->assertInstanceOf(customfield_textarea\field_controller::class, $fields[$textareafield->get('shortname')]);
$data = [
'customfield_mycheckbox' => '1',
'customfield_mydate' => '2019-10-01',
'customfield_myselect' => 'Green',
'customfield_mytext' => 'Hello',
'customfield_myunknownfield' => 'Goodbye',
];
$expected = [
'customfield_mycheckbox' => '1',
'customfield_mydate' => strtotime('2019-10-01'),
'customfield_myselect' => 2,
'customfield_mytext' => 'Hello',
];
$course = $this->getDataGenerator()->create_course();
$user = $this->getDataGenerator()->create_and_enrol($course, 'manager');
$this->setUser($user);
$context = context_course::instance($course->id);
$this->assertEquals($expected, tool_uploadcourse_helper::get_custom_course_field_data($data, [], $context));
// Now add our custom textarea field (separately because the value of it's 'itemid' element is unknown).
$data['customfield_mytextarea'] = 'Something';
$fields = tool_uploadcourse_helper::get_custom_course_field_data($data, [], $context);
$this->assertArrayHasKey('customfield_mytextarea_editor', $fields);
$this->assertArrayHasKey('text', $fields['customfield_mytextarea_editor']);
$this->assertEquals('Something', $fields['customfield_mytextarea_editor']['text']);
// Now prohibit the capability to change locked fields for the manager role.
$managerrole = $DB->get_record('role', ['shortname' => 'manager']);
role_change_permission($managerrole->id, $context, 'moodle/course:changelockedcustomfields', CAP_PROHIBIT);
// The locked 'mytext' custom field should not be returned.
$fields = tool_uploadcourse_helper::get_custom_course_field_data($data, [], $context);
$this->assertCount(4, $fields);
$this->assertArrayNotHasKey('customfield_mytext', $fields);
}
public function test_increment_idnumber() {
$this->resetAfterTest(true);
@@ -394,4 +469,33 @@ class tool_uploadcourse_helper_testcase extends advanced_testcase {
$this->assertEquals($cat3_fakedouble->id, tool_uploadcourse_helper::resolve_category_by_path($path));
$this->assertEquals($cat3_fakedouble->id, tool_uploadcourse_helper::resolve_category_by_path($path));
}
}
/**
* Get custom field plugin generator
*
* @return core_customfield_generator
*/
protected function get_customfield_generator() : core_customfield_generator {
return $this->getDataGenerator()->get_plugin_generator('core_customfield');
}
/**
* Helper method to create custom course field
*
* @param \core_customfield\category_controller $category
* @param string $type
* @param string $shortname
* @param array $configdata
* @return \core_customfield\field_controller
*/
protected function create_custom_field(\core_customfield\category_controller $category, string $type, string $shortname,
array $configdata = []) : \core_customfield\field_controller {
return $this->get_customfield_generator()->create_field([
'categoryid' => $category->get('id'),
'type' => $type,
'shortname' => $shortname,
'configdata' => $configdata,
]);
}
}
+1 -1
View File
@@ -122,7 +122,7 @@ abstract class data_controller {
*
* @return string
*/
protected function get_form_element_name() : string {
public function get_form_element_name() : string {
return 'customfield_' . $this->get_field()->get('shortname');
}
+12
View File
@@ -123,6 +123,18 @@ abstract class field_controller {
return $fieldcontroller;
}
/**
* Perform pre-processing of field values, for example those that originate from an external source (e.g. upload course tool)
*
* Override in plugin classes as necessary
*
* @param string $value
* @return mixed
*/
public function parse_value(string $value) {
return $value;
}
/**
* Validate the data on the field configuration form
*
+12 -3
View File
@@ -638,8 +638,11 @@ abstract class handler {
*
* @param \MoodleQuickForm $mform
* @param int $instanceid id of the instance, can be null when instance is being created
* @param string $headerlangidentifier If specified, a lang string will be used for field category headings
* @param string $headerlangcomponent
*/
public function instance_form_definition(\MoodleQuickForm $mform, int $instanceid = 0) {
public function instance_form_definition(\MoodleQuickForm $mform, int $instanceid = 0,
?string $headerlangidentifier = null, ?string $headerlangcomponent = null) {
$editablefields = $this->get_editable_fields($instanceid);
$fieldswithdata = api::get_instance_fields_data($editablefields, $instanceid);
@@ -647,8 +650,14 @@ abstract class handler {
foreach ($fieldswithdata as $data) {
$categoryid = $data->get_field()->get_category()->get('id');
if ($categoryid != $lastcategoryid) {
$mform->addElement('header', 'category_' . $categoryid,
format_string($data->get_field()->get_category()->get('name')));
$categoryname = format_string($data->get_field()->get_category()->get('name'));
// Load category header lang string if specified.
if (!empty($headerlangidentifier)) {
$categoryname = get_string($headerlangidentifier, $headerlangcomponent, $categoryname);
}
$mform->addElement('header', 'category_' . $categoryid, $categoryname);
$lastcategoryid = $categoryid;
}
$data->instance_form_definition($mform);
@@ -114,4 +114,17 @@ class field_controller extends \core_customfield\field_controller {
$this->get_formatted_name());
return $ret;
}
}
/**
* Convert given value into appropriate timestamp
*
* @param string $value
* @return int
*/
public function parse_value(string $value) {
$timestamp = strtotime($value);
// If we have a valid, positive timestamp then return it.
return $timestamp > 0 ? $timestamp : 0;
}
}
+30 -1
View File
@@ -171,10 +171,39 @@ class customfield_date_plugin_testcase extends advanced_testcase {
$this->assertEquals(null, $d->export_value());
}
/**
* Data provider for {@see test_parse_value}
*
* @return array
*/
public function parse_value_provider() : array {
return [
// Valid times.
['2019-10-01', strtotime('2019-10-01')],
['2019-10-01 14:00', strtotime('2019-10-01 14:00')],
// Invalid times.
['ZZZZZ', 0],
['202-04-01', 0],
['2019-15-15', 0],
];
}
/**
* Test field parse_value method
*
* @param string $value
* @param int $expected
* @return void
*
* @dataProvider parse_value_provider
*/
public function test_parse_value(string $value, int $expected) {
$this->assertSame($expected, $this->cfields[1]->parse_value($value));
}
/**
* Deleting fields and data
*/
public function test_delete() {
$this->cfcat->get_handler()->delete_all();
}
}
}
@@ -119,4 +119,14 @@ class field_controller extends \core_customfield\field_controller {
$this->get_formatted_name());
return $ret;
}
}
/**
* Locate the value parameter in the field options array, and return it's index
*
* @param string $value
* @return int
*/
public function parse_value(string $value) {
return (int) array_search($value, self::get_options_array($this));
}
}
+37 -1
View File
@@ -157,10 +157,46 @@ class customfield_select_plugin_testcase extends advanced_testcase {
$this->assertEquals('b', $d->export_value());
}
/**
* Data provider for {@see test_parse_value}
*
* @return array
*/
public function parse_value_provider() : array {
return [
['Red', 1],
['Blue', 2],
['Green', 3],
['Mauve', 0],
];
}
/**
* Test field parse_value method
*
* @param string $value
* @param int $expected
* @return void
*
* @dataProvider parse_value_provider
*/
public function test_parse_value(string $value, int $expected) {
$field = $this->get_generator()->create_field([
'categoryid' => $this->cfcat->get('id'),
'type' => 'select',
'shortname' => 'myselect',
'configdata' => [
'options' => "Red\nBlue\nGreen",
],
]);
$this->assertSame($expected, $field->parse_value($value));
}
/**
* Deleting fields and data
*/
public function test_delete() {
$this->cfcat->get_handler()->delete_all();
}
}
}
@@ -59,7 +59,7 @@ class data_controller extends \core_customfield\data_controller {
*
* @return string
*/
protected function get_form_element_name() : string {
public function get_form_element_name() : string {
return parent::get_form_element_name() . '_editor';
}