diff --git a/lib/classes/external/exporter.php b/lib/classes/external/exporter.php
index bfaa6ef0918..3fe6673b17e 100644
--- a/lib/classes/external/exporter.php
+++ b/lib/classes/external/exporter.php
@@ -145,13 +145,14 @@ abstract class exporter {
// If the field is PARAM_RAW and has a format field.
if ($propertyformat = self::get_format_field($properties, $property)) {
- if (!property_exists($record, $propertyformat)) {
+ $formatdefinition = $properties[$propertyformat];
+ if (!property_exists($record, $propertyformat) && !array_key_exists('default', $formatdefinition)) {
// Whoops, we got something that wasn't defined.
throw new coding_exception('Unexpected property ' . $propertyformat);
}
$formatparams = $this->get_format_parameters($property);
- $format = $record->$propertyformat;
+ $format = $record->$propertyformat ?? $formatdefinition['default'];
list($text, $format) = \core_external\util::format_text($data->$property, $format, $formatparams['context'],
$formatparams['component'], $formatparams['filearea'], $formatparams['itemid'], $formatparams['options']);
diff --git a/lib/tests/exporter_test.php b/lib/tests/exporter_test.php
index bbcf5b43331..2c91e1c3f3b 100644
--- a/lib/tests/exporter_test.php
+++ b/lib/tests/exporter_test.php
@@ -29,6 +29,7 @@ use core_external\external_multiple_structure;
use core_external\external_settings;
use core_external\external_single_structure;
use core_external\external_value;
+use core_external\util;
/**
* Exporter testcase.
@@ -202,6 +203,49 @@ class exporter_test extends \advanced_testcase {
// Assert nested elements are formatted correctly.
$this->assertEquals('id', $properties['nestedarray']['type']['id']['description']);
}
+
+ /**
+ * Tests for the handling of the default attribute of format properties in exporters.
+ *
+ * @covers \core\external\exporter::export
+ * @return void
+ */
+ public function test_export_format_no_default(): void {
+ global $PAGE;
+ $output = $PAGE->get_renderer('core');
+ $syscontext = \context_system::instance();
+ $related = [
+ 'context' => $syscontext,
+ ] + $this->validrelated;
+
+ // Pass a data that does not have the format property for stringA.
+ $data = [
+ 'stringA' => '__Go to:__ [Moodle.org](https://moodle.org)',
+ 'intB' => 1,
+ ];
+
+ // Note: For testing purposes only. Never extend exporter implementation. Only extend from the base exporter class!
+ $testablexporterclass = new class($data, $related) extends core_testable_exporter {
+ /**
+ * Properties definition.
+ */
+ public static function define_properties(): array {
+ $properties = parent::define_properties();
+ $properties['stringAformat']['default'] = FORMAT_MARKDOWN;
+ return $properties;
+ }
+ };
+ // For a property format with default set, it should be able to export a data even if the property format is not passed.
+ $result = $testablexporterclass->export($output);
+ $expected = 'Go to: Moodle.org';
+ $this->assertStringContainsString($expected, $result->stringA);
+ $this->assertEquals(FORMAT_HTML, $result->stringAformat);
+
+ // Passing data to an exporter with a required property format will throw an exception.
+ $exporter = new core_testable_exporter($data, $related);
+ $this->expectException(\coding_exception::class);
+ $exporter->export($output);
+ }
}
/**