mirror of
https://github.com/moodle/moodle.git
synced 2025-04-21 00:12:56 +02:00
MDL-82571 customfield_number: Display format to number custom field
Add extra settings to the new number custom field in order to allow it format the exported data using placeholders plus supporting multi language.
This commit is contained in:
parent
072fb90384
commit
241fa420d8
@ -892,6 +892,49 @@ final class externallib_test extends externallib_advanced_testcase {
|
||||
'value' => userdate(1580389200),
|
||||
'valueraw' => 1580389200,
|
||||
], reset($course['customfields']));
|
||||
|
||||
// Set the multilang filter to apply to strings + reset filer caches.
|
||||
filter_set_global_state('multilang', TEXTFILTER_ON);
|
||||
filter_set_applies_to_strings('multilang', true);
|
||||
\filter_manager::reset_caches();
|
||||
|
||||
// Let's create a custom field (number), and test the placeholders/multilang display.
|
||||
/** @var core_customfield_generator $cfgenerator */
|
||||
$cfgenerator = $this->getDataGenerator()->get_plugin_generator('core_customfield');
|
||||
$numberfieldata = [
|
||||
'categoryid' => $fieldcategory->get('id'),
|
||||
'name' => 'Price',
|
||||
'shortname' => 'price',
|
||||
'type' => 'number',
|
||||
'configdata' => [
|
||||
'display' => '{value}',
|
||||
'decimalplaces' => 2,
|
||||
],
|
||||
];
|
||||
|
||||
// Create a number custom field with default display template.
|
||||
$numberfield = $cfgenerator->create_field($numberfieldata);
|
||||
$cfgenerator->add_instance_data($numberfield, $newcourse->id, 15);
|
||||
|
||||
// Create a number custom field with multilang display template.
|
||||
$numberfieldata['name'] = 'Price (multilang)';
|
||||
$numberfieldata['shortname'] = 'pricemultilang';
|
||||
$numberfieldata['configdata']['display'] = '<span lang="en" class="multilang">$ {value}</span>'
|
||||
. '<span lang="es" class="multilang">€ {value}</span>';
|
||||
$numberfield1 = $cfgenerator->create_field($numberfieldata);
|
||||
$cfgenerator->add_instance_data($numberfield1, $newcourse->id, 20);
|
||||
|
||||
$courses = external_api::clean_returnvalue(
|
||||
core_course_external::get_courses_returns(),
|
||||
core_course_external::get_courses(['ids' => [$newcourse->id]])
|
||||
);
|
||||
|
||||
$course = reset($courses);
|
||||
$this->assertCount(3, $course['customfields']);
|
||||
|
||||
// Assert the received number custom fields display placeholders correctly with multilang filter when applied.
|
||||
$this->assertEquals('15.00', $course['customfields'][1]['value']);
|
||||
$this->assertEquals('$ 20.00', $course['customfields'][2]['value']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -120,12 +120,8 @@ class data_controller extends \core_customfield\data_controller {
|
||||
* @return string|null
|
||||
*/
|
||||
public function export_value(): ?string {
|
||||
$value = $this->get_value();
|
||||
if ($this->is_empty($value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$decimalplaces = (int) $this->get_field()->get_configdata_property('decimalplaces');
|
||||
return format_float((float) $value, $decimalplaces);
|
||||
/** @var field_controller $field */
|
||||
$field = $this->get_field();
|
||||
return $field->prepare_field_for_display($this->get_value(), $this->get_context());
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,9 @@ declare(strict_types=1);
|
||||
|
||||
namespace customfield_number;
|
||||
|
||||
use core\context\system;
|
||||
use core\context;
|
||||
use html_writer;
|
||||
use MoodleQuickForm;
|
||||
|
||||
/**
|
||||
@ -62,6 +65,29 @@ class field_controller extends \core_customfield\field_controller {
|
||||
$mform->setDefault('configdata[decimalplaces]', 0);
|
||||
}
|
||||
$mform->setType('configdata[decimalplaces]', PARAM_INT);
|
||||
|
||||
// Display format settings.
|
||||
// TODO: Change this after MDL-82996 fixed.
|
||||
$randelname = 'str_' . random_string();
|
||||
$mform->addGroup([], $randelname, html_writer::tag('h4', get_string('headerdisplaysettings', 'customfield_number')));
|
||||
|
||||
// Display template.
|
||||
$mform->addElement('text', 'configdata[display]', get_string('display', 'customfield_number'),
|
||||
['size' => 50]);
|
||||
$mform->setType('configdata[display]', PARAM_TEXT);
|
||||
$mform->addHelpButton('configdata[display]', 'display', 'customfield_number');
|
||||
if ($this->get_configdata_property('display') === null) {
|
||||
$mform->setDefault('configdata[display]', '{value}');
|
||||
}
|
||||
|
||||
// Display when zero.
|
||||
$mform->addElement('text', 'configdata[displaywhenzero]', get_string('displaywhenzero', 'customfield_number'),
|
||||
['size' => 50]);
|
||||
$mform->setType('configdata[displaywhenzero]', PARAM_TEXT);
|
||||
$mform->addHelpButton('configdata[displaywhenzero]', 'displaywhenzero', 'customfield_number');
|
||||
if ($this->get_configdata_property('displaywhenzero') === null) {
|
||||
$mform->setDefault('configdata[displaywhenzero]', 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -74,6 +100,11 @@ class field_controller extends \core_customfield\field_controller {
|
||||
public function config_form_validation(array $data, $files = []): array {
|
||||
$errors = parent::config_form_validation($data, $files);
|
||||
|
||||
$display = $data['configdata']['display'];
|
||||
if (!preg_match('/\{value}/', $display)) {
|
||||
$errors['configdata[display]'] = get_string('displayvalueconfigerror', 'customfield_number');
|
||||
}
|
||||
|
||||
// Each of these configuration fields are optional.
|
||||
$defaultvalue = $data['configdata']['defaultvalue'] ?? '';
|
||||
$minimumvalue = $data['configdata']['minimumvalue'] ?? '';
|
||||
@ -103,4 +134,29 @@ class field_controller extends \core_customfield\field_controller {
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a value for export
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param context|null $context
|
||||
* @return string|null
|
||||
*/
|
||||
public function prepare_field_for_display(mixed $value, ?context $context = null): ?string {
|
||||
if ((float)$value == 0) {
|
||||
$value = $this->get_configdata_property('displaywhenzero');
|
||||
if ((string) $value === '') {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
// Let's format the value.
|
||||
$decimalplaces = (int) $this->get_configdata_property('decimalplaces');
|
||||
$value = format_float((float) $value, $decimalplaces);
|
||||
|
||||
// Apply the display format.
|
||||
$format = $this->get_configdata_property('display');
|
||||
$value = str_replace('{value}', $value, $format);
|
||||
}
|
||||
return format_string($value, true, ['context' => $context ?? system::instance()]);
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,18 @@ defined('MOODLE_INTERNAL') || die;
|
||||
|
||||
$string['decimalplaces'] = 'Decimal places';
|
||||
$string['defaultvalueconfigerror'] = 'Default value must be between minimum and maximum';
|
||||
$string['display'] = 'Display template';
|
||||
$string['display_help'] = 'How to display the value of the field. Use the following placeholders:
|
||||
|
||||
* **{value}** - display value in a general format (float with decimals configured in the field)
|
||||
* **$ {value}** - price in dollars
|
||||
* **{value} hrs** - duration in hours';
|
||||
$string['displayvalueconfigerror'] = 'The placeholder is not invalid';
|
||||
$string['displaywhenzero'] = 'Display when zero';
|
||||
$string['displaywhenzero_help'] = 'How to display the field value when the value is "0". For example, in case of a price you can display the word "Free" but in case of the duration you may want to leave it empty since it means that the duration was not estimated.
|
||||
|
||||
Leave empty if you do not want to display anything at all when the value is set to "0".';
|
||||
$string['headerdisplaysettings'] = 'Display format';
|
||||
$string['maximumvalue'] = 'Maximum value';
|
||||
$string['maximumvalueerror'] = 'Value must be less than or equal to {$a}';
|
||||
$string['minimumvalue'] = 'Minimum value';
|
||||
|
93
customfield/field/number/tests/behat/field.feature
Normal file
93
customfield/field/number/tests/behat/field.feature
Normal file
@ -0,0 +1,93 @@
|
||||
@customfield @customfield_number @javascript
|
||||
Feature: Managers can manage course custom fields number
|
||||
In order to have additional data on the course
|
||||
As a manager
|
||||
I need to create, edit, remove and display number custom fields
|
||||
|
||||
Background:
|
||||
Given the following "custom field categories" exist:
|
||||
| name | component | area | itemid |
|
||||
| Category for test | core_course | course | 0 |
|
||||
And I log in as "admin"
|
||||
And I navigate to "Courses > Default settings > Course custom fields" in site administration
|
||||
|
||||
Scenario: Create a custom course number field
|
||||
When I click on "Add a new custom field" "link"
|
||||
And I click on "Number" "link"
|
||||
When I set the following fields to these values:
|
||||
| Name | Number field |
|
||||
| Short name | numberfield |
|
||||
| Display template | test |
|
||||
And I click on "Save changes" "button" in the "Adding a new Number" "dialogue"
|
||||
Then I should see "The placeholder is not invalid"
|
||||
And I set the following fields to these values:
|
||||
| Name | Number field |
|
||||
| Short name | numberfield |
|
||||
| Display template | {value} |
|
||||
And I click on "Save changes" "button" in the "Adding a new Number" "dialogue"
|
||||
And I should see "Number field"
|
||||
And I log out
|
||||
|
||||
Scenario: Edit a custom course number field
|
||||
When I click on "Add a new custom field" "link"
|
||||
And I click on "Number" "link"
|
||||
And I set the following fields to these values:
|
||||
| Name | Number field |
|
||||
| Short name | numberfield |
|
||||
And I click on "Save changes" "button" in the "Adding a new Number" "dialogue"
|
||||
Then I should see "Number field"
|
||||
And I click on "Edit" "link" in the "Number field" "table_row"
|
||||
And I set the following fields to these values:
|
||||
| Name | Edited number field |
|
||||
And I click on "Save changes" "button" in the "Updating Number field" "dialogue"
|
||||
Then I should see "Edited number field"
|
||||
And I log out
|
||||
|
||||
Scenario: Delete a custom course number field
|
||||
When I click on "Add a new custom field" "link"
|
||||
And I click on "Number" "link"
|
||||
And I set the following fields to these values:
|
||||
| Name | Number field |
|
||||
| Short name | numberfield |
|
||||
And I click on "Save changes" "button" in the "Adding a new Number" "dialogue"
|
||||
And I click on "Delete" "link" in the "Number field" "table_row"
|
||||
And I click on "Yes" "button" in the "Confirm" "dialogue"
|
||||
And I wait until the page is ready
|
||||
And I wait until "Number field" "text" does not exist
|
||||
Then I should not see "Number field"
|
||||
And I log out
|
||||
|
||||
Scenario Outline: A number field must shown correctly on course listing
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | Example 1 | teacher1@example.com |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname | format |
|
||||
| Course 1 | C1 | topics |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
And I navigate to "Courses > Default settings > Course custom fields" in site administration
|
||||
And I click on "Add a new custom field" "link"
|
||||
And I click on "Number" "link"
|
||||
When I set the following fields to these values:
|
||||
| Name | Test number |
|
||||
| Short name | testnumber |
|
||||
| Decimal places | 2 |
|
||||
| Display template | <template> |
|
||||
| Display when zero | <whenzero> |
|
||||
And I click on "Save changes" "button" in the "Adding a new Number" "dialogue"
|
||||
And I log out
|
||||
Then I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "Settings" in current page administration
|
||||
And I set the following fields to these values:
|
||||
| Test number | <fieldvalue> |
|
||||
And I press "Save and display"
|
||||
And I am on site homepage
|
||||
And I should see "Test number" in the ".customfields-container .customfieldname" "css_element"
|
||||
And I should see "<expectedvalue>" in the ".customfields-container .customfieldvalue" "css_element"
|
||||
Examples:
|
||||
| template | whenzero | fieldvalue | expectedvalue |
|
||||
| $ {value} | 0 | 150 | $ 150.00 |
|
||||
| {value} | Free | 0 | Free |
|
@ -121,22 +121,66 @@ final class data_controller_test extends advanced_testcase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test exporting instance
|
||||
* Data provider for {@see test_export_value}
|
||||
*
|
||||
* @return array[]
|
||||
*/
|
||||
public function test_export_value(): void {
|
||||
public static function export_value_provider(): array {
|
||||
$template = '<span class="multilang" lang="en">$ {value}</span><span class="multilang" lang="es">€ {value}</span>';
|
||||
$whenzero = '<span class="multilang" lang="en">Unknown</span><span class="multilang" lang="es">Desconocido</span>';
|
||||
return [
|
||||
'Export float value' => [42, 42.0, [
|
||||
'decimalplaces' => 2,
|
||||
'display' => '{value}',
|
||||
'displaywhenzero' => 0],
|
||||
],
|
||||
'Export value with a prefix' => [10, '$ 10.00', [
|
||||
'decimalplaces' => 2,
|
||||
'display' => $template,
|
||||
'displaywhenzero' => 0],
|
||||
],
|
||||
'Export value when zero' => [0, 'Unknown', [
|
||||
'display' => '{value}',
|
||||
'displaywhenzero' => $whenzero],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Test exporting instance
|
||||
*
|
||||
* @param float|string $datavalue
|
||||
* @param float|string $expectedvalue
|
||||
* @param array $configdata
|
||||
*
|
||||
* @dataProvider export_value_provider
|
||||
*/
|
||||
public function test_export_value(
|
||||
float|string $datavalue,
|
||||
float|string $expectedvalue,
|
||||
array $configdata,
|
||||
): void {
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
|
||||
// Enable multilang filter.
|
||||
filter_set_global_state('multilang', TEXTFILTER_ON);
|
||||
filter_set_applies_to_strings('multilang', true);
|
||||
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
|
||||
/** @var core_customfield_generator $generator */
|
||||
$generator = $this->getDataGenerator()->get_plugin_generator('core_customfield');
|
||||
|
||||
$category = $generator->create_category();
|
||||
$field = $generator->create_field(['categoryid' => $category->get('id'), 'type' => 'number']);
|
||||
$data = $generator->add_instance_data($field, (int) $course->id, 42);
|
||||
$field = $generator->create_field([
|
||||
'categoryid' => $category->get('id'),
|
||||
'type' => 'number',
|
||||
'configdata' => $configdata,
|
||||
]);
|
||||
$data = $generator->add_instance_data($field, (int) $course->id, $datavalue);
|
||||
|
||||
$result = \core_customfield\data_controller::create($data->get('id'))->export_value();
|
||||
$this->assertEquals(42.0, $result);
|
||||
$this->assertEquals($expectedvalue, $result);
|
||||
}
|
||||
}
|
||||
|
@ -55,11 +55,13 @@ final class field_controller_test extends advanced_testcase {
|
||||
*/
|
||||
public static function form_definition_provider(): array {
|
||||
return [
|
||||
'Defaults' => ['', '', '', true],
|
||||
'Minimum greater than maximum' => ['', 12, 10, false],
|
||||
'Default value less than minimum' => [1, 10, 12, false],
|
||||
'Default value greater than maximum' => [13, 10, 12, false],
|
||||
'Valid' => [11, 10, 12, true],
|
||||
'Defaults' => ['', '', '', '{value}', true],
|
||||
'Minimum greater than maximum' => ['', 12, 10, '{value}', false],
|
||||
'Default value less than minimum' => [1, 10, 12, '{value}', false],
|
||||
'Default value greater than maximum' => [13, 10, 12, '{value}', false],
|
||||
'Valid' => [11, 10, 12, '{value}', true],
|
||||
'Display valid single placeholder' => ['', '', '', '{value}', true],
|
||||
'Display invalid single placeholder' => ['', '', '', '111', false],
|
||||
];
|
||||
}
|
||||
|
||||
@ -69,6 +71,7 @@ final class field_controller_test extends advanced_testcase {
|
||||
* @param float|string $defaultvalue
|
||||
* @param float|string $minimumvalue
|
||||
* @param float|string $maximumvalue
|
||||
* @param string $display
|
||||
* @param bool $expected
|
||||
*
|
||||
* @dataProvider form_definition_provider
|
||||
@ -77,6 +80,7 @@ final class field_controller_test extends advanced_testcase {
|
||||
float|string $defaultvalue,
|
||||
float|string $minimumvalue,
|
||||
float|string $maximumvalue,
|
||||
string $display,
|
||||
bool $expected,
|
||||
): void {
|
||||
$this->resetAfterTest();
|
||||
@ -93,6 +97,7 @@ final class field_controller_test extends advanced_testcase {
|
||||
'defaultvalue' => $defaultvalue,
|
||||
'minimumvalue' => $minimumvalue,
|
||||
'maximumvalue' => $maximumvalue,
|
||||
'display' => $display,
|
||||
]);
|
||||
|
||||
$formdata = field_config_form::mock_ajax_submit($submitdata);
|
||||
|
Loading…
x
Reference in New Issue
Block a user