From 4bc68a416ef7401a44ccbabba25dcfeefad4eeb5 Mon Sep 17 00:00:00 2001 From: Frederic Massart Date: Thu, 15 Dec 2016 18:03:40 +0800 Subject: [PATCH] MDL-57273 core: Exporters support custom formatting parameters --- .../external/competency_path_exporter.php | 2 +- .../classes/external/path_node_exporter.php | 29 +++++++ .../user_competency_summary_exporter.php | 1 + admin/tool/lp/tests/externallib_test.php | 18 +++++ competency/classes/evidence.php | 9 +++ competency/classes/external.php | 3 + .../competency_framework_exporter.php | 4 +- .../classes/external/evidence_exporter.php | 34 +++++++- .../user_competency_course_exporter.php | 13 ++- .../external/user_competency_exporter.php | 12 +++ .../user_competency_plan_exporter.php | 12 +++ competency/tests/external_test.php | 47 +++++++++++ lib/classes/external/exporter.php | 75 +++++++++++++++--- lib/classes/external/persistent_exporter.php | 2 +- lib/tests/exporter_test.php | 79 ++++++++++++++++--- .../external/user_summary_exporter.php | 24 ++++++ 16 files changed, 334 insertions(+), 30 deletions(-) diff --git a/admin/tool/lp/classes/external/competency_path_exporter.php b/admin/tool/lp/classes/external/competency_path_exporter.php index 01ecd8d32dcfb..e5f11af67c97b 100644 --- a/admin/tool/lp/classes/external/competency_path_exporter.php +++ b/admin/tool/lp/classes/external/competency_path_exporter.php @@ -72,7 +72,7 @@ protected static function define_other_properties() { 'type' => path_node_exporter::read_properties_definition() ], 'pluginbaseurl' => [ - 'type' => PARAM_TEXT + 'type' => PARAM_URL ], 'pagecontextid' => [ 'type' => PARAM_INT diff --git a/admin/tool/lp/classes/external/path_node_exporter.php b/admin/tool/lp/classes/external/path_node_exporter.php index 0d74411a68faf..93ef8ccf90d66 100644 --- a/admin/tool/lp/classes/external/path_node_exporter.php +++ b/admin/tool/lp/classes/external/path_node_exporter.php @@ -24,6 +24,7 @@ namespace tool_lp\external; defined('MOODLE_INTERNAL') || die(); +use context_system; /** * Class for exporting path_node data. @@ -33,6 +34,34 @@ */ class path_node_exporter extends \core\external\exporter { + /** + * Constructor - saves the persistent object, and the related objects. + * + * @param mixed $data The data. + * @param array $related Array of relateds. + */ + public function __construct($data, $related = array()) { + if (!isset($related['context'])) { + // Previous code was automatically using the system context which was not always correct. + // We let developers know that they must fix their code without breaking anything, + // and fallback on the previous behaviour. This should be removed at a later stage: Moodle 3.5. + debugging('Missing related context in path_node_exporter.', DEBUG_DEVELOPER); + $related['context'] = context_system::instance(); + } + parent::__construct($data, $related); + } + + /** + * Return the list of properties. + * + * @return array + */ + protected static function define_related() { + return [ + 'context' => 'context' + ]; + } + /** * Return the list of properties. * diff --git a/admin/tool/lp/classes/external/user_competency_summary_exporter.php b/admin/tool/lp/classes/external/user_competency_summary_exporter.php index 1426c5b6731d1..87e999a6b0c19 100644 --- a/admin/tool/lp/classes/external/user_competency_summary_exporter.php +++ b/admin/tool/lp/classes/external/user_competency_summary_exporter.php @@ -154,6 +154,7 @@ protected function get_other_values(renderer_base $output) { 'scale' => $scale, 'usercompetency' => ($this->related['usercompetency'] ? $this->related['usercompetency'] : null), 'usercompetencyplan' => ($this->related['usercompetencyplan'] ? $this->related['usercompetencyplan'] : null), + 'context' => $evidence->get_context() ); $related['actionuser'] = !empty($actionuserid) ? $usercache[$actionuserid] : null; $exporter = new evidence_exporter($evidence, $related); diff --git a/admin/tool/lp/tests/externallib_test.php b/admin/tool/lp/tests/externallib_test.php index 1c85942ea5a3e..855d02ff6f0f3 100644 --- a/admin/tool/lp/tests/externallib_test.php +++ b/admin/tool/lp/tests/externallib_test.php @@ -443,6 +443,24 @@ public function test_data_for_user_competency_summary_in_plan() { $this->assertEquals('A', $summary->usercompetencysummary->evidence[1]->gradename); } + public function test_data_for_user_competency_summary() { + $this->setUser($this->creator); + + $dg = $this->getDataGenerator(); + $lpg = $dg->get_plugin_generator('core_competency'); + $f1 = $lpg->create_framework(); + $c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id())); + + $evidence = \core_competency\external::grade_competency($this->user->id, $c1->get_id(), 1, true); + $evidence = \core_competency\external::grade_competency($this->user->id, $c1->get_id(), 2, true); + + $summary = external::data_for_user_competency_summary($this->user->id, $c1->get_id()); + $this->assertTrue($summary->cangrade); + $this->assertEquals('B', $summary->usercompetency->gradename); + $this->assertEquals('B', $summary->evidence[0]->gradename); + $this->assertEquals('A', $summary->evidence[1]->gradename); + } + /** * Search cohorts. */ diff --git a/competency/classes/evidence.php b/competency/classes/evidence.php index 40e1448f4405a..03d63a4d96dc5 100644 --- a/competency/classes/evidence.php +++ b/competency/classes/evidence.php @@ -110,6 +110,15 @@ public function get_competency() { return user_competency::get_competency_by_usercompetencyid($this->get_usercompetencyid()); } + /** + * Return the evidence's context. + * + * @return context + */ + public function get_context() { + return context::instance_by_id($this->get('contextid')); + } + /** * Convenience method to get the description $a. * diff --git a/competency/classes/external.php b/competency/classes/external.php index 06369a5e0d999..bb6755ee04b4d 100644 --- a/competency/classes/external.php +++ b/competency/classes/external.php @@ -3709,6 +3709,7 @@ public static function grade_competency($userid, $competencyid, $grade, $note = 'scale' => $scale, 'usercompetency' => $uc, 'usercompetencyplan' => null, + 'context' => $evidence->get_context() ]); return $exporter->export($output); } @@ -3795,6 +3796,7 @@ public static function grade_competency_in_plan($planid, $competencyid, $grade, 'scale' => $scale, 'usercompetency' => null, 'usercompetencyplan' => null, + 'context' => $evidence->get_context() ]); return $exporter->export($output); } @@ -4107,6 +4109,7 @@ public static function grade_competency_in_course($courseid, $userid, $competenc 'scale' => $scale, 'usercompetency' => null, 'usercompetencyplan' => null, + 'context' => $evidence->get_context(), )); return $exporter->export($output); } diff --git a/competency/classes/external/competency_framework_exporter.php b/competency/classes/external/competency_framework_exporter.php index e285659984cc8..16ed16c4517c0 100644 --- a/competency/classes/external/competency_framework_exporter.php +++ b/competency/classes/external/competency_framework_exporter.php @@ -75,10 +75,10 @@ protected static function define_other_properties() { 'type' => PARAM_INT ), 'contextname' => array( - 'type' => PARAM_TEXT + 'type' => PARAM_RAW ), 'contextnamenoprefix' => array( - 'type' => PARAM_TEXT + 'type' => PARAM_RAW ) ); } diff --git a/competency/classes/external/evidence_exporter.php b/competency/classes/external/evidence_exporter.php index 935b1d92e95e0..3e07e602ca77c 100644 --- a/competency/classes/external/evidence_exporter.php +++ b/competency/classes/external/evidence_exporter.php @@ -24,6 +24,7 @@ namespace core_competency\external; defined('MOODLE_INTERNAL') || die(); +use context_system; use renderer_base; use core_competency\evidence; use core_competency\user_competency; @@ -37,9 +38,27 @@ */ class evidence_exporter extends \core\external\persistent_exporter { + /** + * Constructor. + * + * @param mixed $data The data. + * @param array $related Array of relateds. + */ + public function __construct($data, $related = array()) { + if (!isset($related['context'])) { + // Previous code was automatically using the system context which was not correct. + // We let developers know that they must fix their code without breaking anything, and + // fallback on the previous behaviour. This should be removed at a later stage: Moodle 3.5. + debugging('Missing related context in evidence_exporter.', DEBUG_DEVELOPER); + $related['context'] = context_system::instance(); + } + parent::__construct($data, $related); + } + protected static function define_related() { return array( 'actionuser' => 'stdClass?', + 'context' => 'context', 'scale' => 'grade_scale', 'usercompetency' => 'core_competency\\user_competency?', 'usercompetencyplan' => 'core_competency\\user_competency_plan?', @@ -85,6 +104,17 @@ protected function get_other_values(renderer_base $output) { return $other; } + /** + * Get the format parameters for gradename. + * + * @return array + */ + protected function get_format_parameters_for_gradename() { + return [ + 'context' => context_system::instance(), // The system context is cached, so we can get it right away. + ]; + } + public static function define_other_properties() { return array( 'actionuser' => array( @@ -92,13 +122,13 @@ public static function define_other_properties() { 'optional' => true ), 'description' => array( - 'type' => PARAM_TEXT, + 'type' => PARAM_TEXT, // The description may contain course names, etc.. which may need filtering. ), 'gradename' => array( 'type' => PARAM_TEXT, ), 'userdate' => array( - 'type' => PARAM_TEXT + 'type' => PARAM_NOTAGS ), 'candelete' => array( 'type' => PARAM_BOOL diff --git a/competency/classes/external/user_competency_course_exporter.php b/competency/classes/external/user_competency_course_exporter.php index 2dc1ecf298cbe..706bd74d8a742 100644 --- a/competency/classes/external/user_competency_course_exporter.php +++ b/competency/classes/external/user_competency_course_exporter.php @@ -24,7 +24,7 @@ namespace core_competency\external; defined('MOODLE_INTERNAL') || die(); -use core_user; +use context_system; use renderer_base; use stdClass; @@ -65,6 +65,17 @@ protected function get_other_values(renderer_base $output) { return (array) $result; } + /** + * Get the format parameters for gradename. + * + * @return array + */ + protected function get_format_parameters_for_gradename() { + return [ + 'context' => context_system::instance(), // The system context is cached, so we can get it right away. + ]; + } + protected static function define_other_properties() { return array( 'gradename' => array( diff --git a/competency/classes/external/user_competency_exporter.php b/competency/classes/external/user_competency_exporter.php index 2c965ea0673c4..019fb1f52a269 100644 --- a/competency/classes/external/user_competency_exporter.php +++ b/competency/classes/external/user_competency_exporter.php @@ -24,6 +24,7 @@ namespace core_competency\external; defined('MOODLE_INTERNAL') || die(); +use context_system; use core_user; use renderer_base; use stdClass; @@ -94,6 +95,17 @@ protected function get_other_values(renderer_base $output) { return (array) $result; } + /** + * Get the format parameters for gradename. + * + * @return array + */ + protected function get_format_parameters_for_gradename() { + return [ + 'context' => context_system::instance(), // The system context is cached, so we can get it right away. + ]; + } + protected static function define_other_properties() { return array( 'canrequestreview' => array( diff --git a/competency/classes/external/user_competency_plan_exporter.php b/competency/classes/external/user_competency_plan_exporter.php index 1749784096dda..bfc6acc511065 100644 --- a/competency/classes/external/user_competency_plan_exporter.php +++ b/competency/classes/external/user_competency_plan_exporter.php @@ -24,6 +24,7 @@ namespace core_competency\external; defined('MOODLE_INTERNAL') || die(); +use context_system; use renderer_base; use stdClass; @@ -64,6 +65,17 @@ protected function get_other_values(renderer_base $output) { return (array) $result; } + /** + * Get the format parameters for gradename. + * + * @return array + */ + protected function get_format_parameters_for_gradename() { + return [ + 'context' => context_system::instance(), // The system context is cached, so we can get it right away. + ]; + } + protected static function define_other_properties() { return array( 'gradename' => array( diff --git a/competency/tests/external_test.php b/competency/tests/external_test.php index 38d7af31be266..fcf7177a936d2 100644 --- a/competency/tests/external_test.php +++ b/competency/tests/external_test.php @@ -2681,6 +2681,53 @@ public function test_fix_sortorder_when_moving_competency() { $this->assertEquals(2, $c2a->get_sortorder()); } + public function test_grade_competency() { + global $CFG; + + $this->setUser($this->creator); + $dg = $this->getDataGenerator(); + $lpg = $dg->get_plugin_generator('core_competency'); + + $f1 = $lpg->create_framework(); + $c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id())); + $evidence = external::grade_competency($this->user->id, $c1->get_id(), 1, 'Evil note'); + + $this->assertEquals('The competency rating was manually set.', $evidence->description); + $this->assertEquals('A', $evidence->gradename); + $this->assertEquals('Evil note', $evidence->note); + + $this->setUser($this->user); + + $this->expectException('required_capability_exception'); + $evidence = external::grade_competency($this->user->id, $c1->get_id(), 1); + } + + public function test_grade_competency_in_course() { + global $CFG; + + $this->setUser($this->creator); + $dg = $this->getDataGenerator(); + $lpg = $dg->get_plugin_generator('core_competency'); + + $course = $dg->create_course(['fullname' => 'Evil course']); + $dg->enrol_user($this->creator->id, $course->id, 'editingteacher'); + $dg->enrol_user($this->user->id, $course->id, 'student'); + $f1 = $lpg->create_framework(); + $c1 = $lpg->create_competency(['competencyframeworkid' => $f1->get_id()]); + $lpg->create_course_competency(['courseid' => $course->id, 'competencyid' => $c1->get_id()]); + + $evidence = external::grade_competency_in_course($course->id, $this->user->id, $c1->get_id(), 1, 'Evil note'); + + $this->assertEquals('The competency rating was manually set in the course \'Course: Evil course\'.', $evidence->description); + $this->assertEquals('A', $evidence->gradename); + $this->assertEquals('Evil note', $evidence->note); + + $this->setUser($this->user); + + $this->expectException('required_capability_exception'); + $evidence = external::grade_competency_in_course($course->id, $this->user->id, $c1->get_id(), 1); + } + public function test_grade_competency_in_plan() { global $CFG; diff --git a/lib/classes/external/exporter.php b/lib/classes/external/exporter.php index e2ca5497eadc3..9539e543a1e0a 100644 --- a/lib/classes/external/exporter.php +++ b/lib/classes/external/exporter.php @@ -116,7 +116,6 @@ public function __construct($data, $related = array()) { final public function export(renderer_base $output) { $data = new stdClass(); $properties = self::read_properties_definition(); - $context = $this->get_context(); $values = (array) $this->data; $othervalues = $this->get_other_values($output); @@ -150,18 +149,27 @@ final public function export(renderer_base $output) { // Whoops, we got something that wasn't defined. throw new coding_exception('Unexpected property ' . $propertyformat); } + + $formatparams = $this->get_format_parameters($property); $format = $record->$propertyformat; - list($text, $format) = external_format_text($data->$property, $format, $context->id, 'core', '', 0); + + list($text, $format) = external_format_text($data->$property, $format, $formatparams['context']->id, + $formatparams['component'], $formatparams['filearea'], $formatparams['itemid'], $formatparams['options']); + $data->$property = $text; $data->$propertyformat = $format; } else if ($definition['type'] === PARAM_TEXT) { + $formatparams = $this->get_format_parameters($property); + if (!empty($definition['multiple'])) { foreach ($data->$property as $key => $value) { - $data->{$property}[$key] = external_format_string($value, $context->id); + $data->{$property}[$key] = external_format_string($value, $formatparams['context']->id, + $formatparams['striplinks'], $formatparams['options']); } } else { - $data->$property = external_format_string($data->$property, $context->id); + $data->$property = external_format_string($data->$property, $formatparams['context']->id, + $formatparams['striplinks'], $formatparams['options']); } } } @@ -170,18 +178,52 @@ final public function export(renderer_base $output) { } /** - * Function to guess the correct context, falling back to system context. + * Get the format parameters. * - * @return context + * This method returns the parameters to use with the functions external_format_text(), and + * external_format_string(). To override the default parameters, you can define a protected method + * called 'get_format_parameters_for_'. For example, 'get_format_parameters_for_description', + * if your property is 'description'. + * + * Your method must return an array containing any of the following keys: + * - context: The context to use. Defaults to $this->related['context'] if defined, else throws an exception. + * - component: The component to use with external_format_text(). Defaults to null. + * - filearea: The filearea to use with external_format_text(). Defaults to null. + * - itemid: The itemid to use with external_format_text(). Defaults to null. + * - options: An array of options accepted by external_format_text() or external_format_string(). Defaults to []. + * - striplinks: Whether to strip the links with external_format_string(). Defaults to true. + * + * @param string $property The property to get the parameters for. + * @return array */ - protected function get_context() { - $context = null; - if (isset($this->related['context']) && $this->related['context'] instanceof context) { - $context = $this->related['context']; - } else { - $context = context_system::instance(); + final protected function get_format_parameters($property) { + $parameters = [ + 'component' => null, + 'filearea' => null, + 'itemid' => null, + 'options' => [], + 'striplinks' => true, + ]; + + $candidate = 'get_format_parameters_for_' . $property; + if (method_exists($this, $candidate)) { + $parameters = array_merge($parameters, $this->{$candidate}()); } - return $context; + + if (!isset($parameters['context'])) { + if (!isset($this->related['context']) || !($this->related['context'] instanceof context)) { + throw new coding_exception("Unknown context to use for formatting the property '$property' in the " . + "exporter '" . get_class($this) . "'. You either need to add 'context' to your related objects, " . + "or create the method '$candidate' and return the context from there."); + } + $parameters['context'] = $this->related['context']; + + } else if (!($parameters['context'] instanceof context)) { + throw new coding_exception("The context given to format the property '$property' in the exporter '" . + get_class($this) . "' is invalid."); + } + + return $parameters; } /** @@ -291,6 +333,13 @@ protected static function define_other_properties() { * The format of the array returned by this method has to match the structure * defined in {@link \core\persistent::define_properties()}. * + * Note that the type PARAM_TEXT should ONLY be used for strings which need to + * go through filters (multilang, etc...) and do not have a FORMAT_* associated + * to them. Typically strings passed through to format_string(). + * + * Other filtered strings which use a FORMAT_* constant (hear used with format_text) + * must be defined as PARAM_RAW. + * * @return array */ protected static function define_properties() { diff --git a/lib/classes/external/persistent_exporter.php b/lib/classes/external/persistent_exporter.php index 3759916c822d0..2fc49f0e7851d 100644 --- a/lib/classes/external/persistent_exporter.php +++ b/lib/classes/external/persistent_exporter.php @@ -47,7 +47,7 @@ abstract class persistent_exporter extends exporter { * @param \core\persistent $persistent The persistent object to export. * @param array $related - An optional list of pre-loaded objects related to this persistent. */ - public final function __construct(\core\persistent $persistent, $related = array()) { + public function __construct(\core\persistent $persistent, $related = array()) { $classname = static::define_class(); if (!$persistent instanceof $classname) { throw new coding_exception('Invalid type for persistent. ' . diff --git a/lib/tests/exporter_test.php b/lib/tests/exporter_test.php index 5a606199e332b..3c126075d74ad 100644 --- a/lib/tests/exporter_test.php +++ b/lib/tests/exporter_test.php @@ -41,8 +41,8 @@ class core_exporter_testcase extends advanced_testcase { public function setUp() { $s = new stdClass(); - $this->validrelated = array('simplestdClass' => $s, 'arrayofstdClass' => array($s, $s)); - $this->invalidrelated = array('simplestdClass' => 'a string', 'arrayofstdClass' => 5); + $this->validrelated = array('simplestdClass' => $s, 'arrayofstdClass' => array($s, $s), 'context' => null); + $this->invalidrelated = array('simplestdClass' => 'a string', 'arrayofstdClass' => 5, 'context' => null); $this->validdata = array('stringA' => 'A string', 'stringAformat' => FORMAT_HTML, 'intB' => 4); @@ -88,7 +88,7 @@ public function test_get_update_structure() { public function test_invalid_data() { global $PAGE; $exporter = new core_testable_exporter($this->invaliddata, $this->validrelated); - $output = $PAGE->get_renderer('tool_lp'); + $output = $PAGE->get_renderer('core'); $result = $exporter->export($output); } @@ -99,21 +99,59 @@ public function test_invalid_data() { public function test_invalid_related() { global $PAGE; $exporter = new core_testable_exporter($this->validdata, $this->invalidrelated); - $output = $PAGE->get_renderer('tool_lp'); + $output = $PAGE->get_renderer('core'); $result = $exporter->export($output); } public function test_valid_data_and_related() { global $PAGE; + $output = $PAGE->get_renderer('core'); $exporter = new core_testable_exporter($this->validdata, $this->validrelated); + $result = $exporter->export($output); + $this->assertSame('>Another string', $result->otherstring); + $this->assertSame(array('String >a', 'String b'), $result->otherstrings); + } - $output = $PAGE->get_renderer('tool_lp'); + public function test_format_text() { + global $PAGE; + $this->resetAfterTest(); + $course = $this->getDataGenerator()->create_course(); + $syscontext = context_system::instance(); + $coursecontext = context_course::instance($course->id); + + external_settings::get_instance()->set_filter(true); + filter_set_global_state('urltolink', TEXTFILTER_OFF); + filter_set_local_state('urltolink', $coursecontext->id, TEXTFILTER_ON); + set_config('formats', FORMAT_MARKDOWN, 'filter_urltolink'); + filter_manager::reset_caches(); + + $data = [ + 'stringA' => '__Watch out:__ https://moodle.org @@PLUGINFILE@@/test.pdf', + 'stringAformat' => FORMAT_MARKDOWN, + 'intB' => 1 + ]; + + // Export simulated in the system context. + $output = $PAGE->get_renderer('core'); + $exporter = new core_testable_exporter($data, ['context' => $syscontext] + $this->validrelated); $result = $exporter->export($output); - $this->assertSame('Another string', $result->otherstring); - $this->assertSame(array('String a', 'String b'), $result->otherstrings); + $youtube = 'https://moodle.org'; + $fileurl = (new moodle_url('/webservice/pluginfile.php/' . $syscontext->id . '/test/area/9/test.pdf'))->out(false); + $expected = "

Watch out: $youtube $fileurl

\n"; + $this->assertEquals($expected, $result->stringA); + $this->assertEquals(FORMAT_HTML, $result->stringAformat); + + // Export simulated in the course context where the filter is enabled. + $exporter = new core_testable_exporter($data, ['context' => $coursecontext] + $this->validrelated); + $result = $exporter->export($output); + $youtube = 'https://moodle.org'; + $fileurl = (new moodle_url('/webservice/pluginfile.php/' . $coursecontext->id . '/test/area/9/test.pdf'))->out(false); + $expected = "

Watch out: $youtube $fileurl

\n"; + $this->assertEquals($expected, $result->stringA); + $this->assertEquals(FORMAT_HTML, $result->stringAformat); } } @@ -128,13 +166,13 @@ class core_testable_exporter extends \core\external\exporter { protected static function define_related() { // We cache the context so it does not need to be retrieved from the course. - return array('simplestdClass' => 'stdClass', 'arrayofstdClass' => 'stdClass[]'); + return array('simplestdClass' => 'stdClass', 'arrayofstdClass' => 'stdClass[]', 'context' => 'context?'); } protected function get_other_values(renderer_base $output) { return array( - 'otherstring' => 'Another string', - 'otherstrings' => array('String a', 'String b') + 'otherstring' => '>Another string', + 'otherstrings' => array('String >a', 'String b') ); } @@ -164,5 +202,26 @@ public static function define_other_properties() { ); } + protected function get_format_parameters_for_stringA() { + return [ + // For testing use the passed context if any. + 'context' => isset($this->related['context']) ? $this->related['context'] : context_system::instance(), + 'component' => 'test', + 'filearea' => 'area', + 'itemid' => 9, + ]; + } + + protected function get_format_parameters_for_otherstring() { + return [ + 'context' => context_system::instance(), + 'options' => ['escape' => false] + ]; + } + protected function get_format_parameters_for_otherstrings() { + return [ + 'context' => context_system::instance(), + ]; + } } diff --git a/user/classes/external/user_summary_exporter.php b/user/classes/external/user_summary_exporter.php index c93aea05bd4d8..f8f21dc767f5f 100644 --- a/user/classes/external/user_summary_exporter.php +++ b/user/classes/external/user_summary_exporter.php @@ -24,6 +24,7 @@ namespace core_user\external; defined('MOODLE_INTERNAL') || die(); +use context_system; use renderer_base; use moodle_url; @@ -66,6 +67,29 @@ protected function get_other_values(renderer_base $output) { ); } + + /** + * Get the format parameters for department. + * + * @return array + */ + protected function get_format_parameters_for_department() { + return [ + 'context' => context_system::instance(), // The system context is cached, so we can get it right away. + ]; + } + + /** + * Get the format parameters for institution. + * + * @return array + */ + protected function get_format_parameters_for_institution() { + return [ + 'context' => context_system::instance(), // The system context is cached, so we can get it right away. + ]; + } + public static function define_properties() { return array( 'id' => array(