From d04ea1665e860219e3e9de2997d3564c415bb272 Mon Sep 17 00:00:00 2001 From: Damyon Wiese Date: Mon, 23 Nov 2015 15:57:56 +0800 Subject: [PATCH] MDL-51041 cbe: Refactor to allow non-persistent exporters --- admin/tool/lp/classes/external.php | 3 +- ...ompetency_with_linked_courses_exporter.php | 81 ++++ .../external/course_summary_exporter.php | 72 +++ admin/tool/lp/classes/external/exporter.php | 428 ++++++++++++++++++ .../classes/external/persistent_exporter.php | 316 +------------ .../lp/classes/external/plan_exporter.php | 4 +- .../lp/classes/external/template_exporter.php | 4 +- .../external/user_competency_exporter.php | 4 +- .../user_competency_plan_exporter.php | 4 +- .../output/template_competencies_page.php | 18 +- .../template_competencies_page.mustache | 6 +- 11 files changed, 609 insertions(+), 331 deletions(-) create mode 100644 admin/tool/lp/classes/external/competency_with_linked_courses_exporter.php create mode 100644 admin/tool/lp/classes/external/course_summary_exporter.php create mode 100644 admin/tool/lp/classes/external/exporter.php diff --git a/admin/tool/lp/classes/external.php b/admin/tool/lp/classes/external.php index 011d384955e..310a1751e50 100644 --- a/admin/tool/lp/classes/external.php +++ b/admin/tool/lp/classes/external.php @@ -39,6 +39,7 @@ use external_multiple_structure; use invalid_parameter_exception; use grade_scale; use tool_lp\external\competency_framework_exporter; +use tool_lp\external\competency_with_linked_courses_exporter; use tool_lp\external\user_competency_exporter; use tool_lp\external\user_competency_plan_exporter; use tool_lp\external\competency_exporter; @@ -2640,7 +2641,7 @@ class external extends external_api { 'canmanagecompetencyframeworks' => new external_value(PARAM_BOOL, 'User can manage competency frameworks'), 'canmanagetemplates' => new external_value(PARAM_BOOL, 'User can manage learning plan templates'), 'competencies' => new external_multiple_structure( - competency_exporter::get_read_structure() + competency_with_linked_courses_exporter::get_read_structure() ), 'manageurl' => new external_value(PARAM_LOCALURL, 'Url to the manage competencies page.'), )); diff --git a/admin/tool/lp/classes/external/competency_with_linked_courses_exporter.php b/admin/tool/lp/classes/external/competency_with_linked_courses_exporter.php new file mode 100644 index 00000000000..c334e4eeb00 --- /dev/null +++ b/admin/tool/lp/classes/external/competency_with_linked_courses_exporter.php @@ -0,0 +1,81 @@ +. + +/** + * Class for exporting competency data with the set of linked courses. + * + * @package tool_lp + * @copyright 2015 Damyon Wiese + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +namespace tool_lp\external; + +use context_course; +use renderer_base; +use stdClass; + +/** + * Class for exporting competency data. + * + * @copyright 2015 Damyon Wiese + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class competency_with_linked_courses_exporter extends exporter { + + protected static function define_related() { + // We cache the context so it does not need to be retrieved from the framework every time. + return array('context' => '\\context', + 'competency' => '\\tool_lp\\competency', + 'linkedcourses' => '\\stdClass[]'); + } + + protected static function define_other_properties() { + return array( + 'linkedcourses' => array( + 'type' => course_summary_exporter::properties_definition(true), + 'multiple' => true + ), + 'competency' => array( + 'type' => competency_exporter::properties_definition(true) + ), + 'hascourses' => array( + 'type' => PARAM_BOOL + ) + ); + } + + protected function get_other_values(renderer_base $output) { + $result = new stdClass(); + + $courses = $this->related['linkedcourses']; + $linkedcourses = array(); + foreach ($courses as $course) { + $context = context_course::instance($course->id); + $exporter = new course_summary_exporter($course, array('context' => $context)); + $courseexport = $exporter->export($output); + array_push($linkedcourses, $courseexport); + } + $result->linkedcourses = $linkedcourses; + $result->hascourses = count($linkedcourses) > 0; + + $competency = $this->related['competency']; + $context = $this->related['context']; + $exporter = new competency_exporter($competency, array('context' => $context)); + $result->competency = $exporter->export($output); + + return (array) $result; + } +} diff --git a/admin/tool/lp/classes/external/course_summary_exporter.php b/admin/tool/lp/classes/external/course_summary_exporter.php new file mode 100644 index 00000000000..9e2ce692849 --- /dev/null +++ b/admin/tool/lp/classes/external/course_summary_exporter.php @@ -0,0 +1,72 @@ +. + +/** + * Class for exporting a course summary from an stdClass. + * + * @package tool_lp + * @copyright 2015 Damyon Wiese + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +namespace tool_lp\external; + +use renderer_base; +use moodle_url; + +/** + * Class for exporting a course summary from an stdClass. + * + * @copyright 2015 Damyon Wiese + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class course_summary_exporter extends exporter { + + protected static function define_related() { + // We cache the context so it does not need to be retrieved from the course. + return array('context' => '\\context'); + } + + protected function get_other_values(renderer_base $output) { + return array( + 'viewurl' => new moodle_url('course/view.php', array('id' => $this->data->id)) + ); + } + + public static function define_properties() { + return array( + 'id' => array( + 'type' => PARAM_INT, + ), + 'fullname' => array( + 'type' => PARAM_TEXT, + ), + 'shortname' => array( + 'type' => PARAM_TEXT, + ), + 'idnumber' => array( + 'type' => PARAM_TEXT, + ) + ); + } + + public static function define_other_properties() { + return array( + 'viewurl' => array( + 'type' => PARAM_URL, + ) + ); + } +} diff --git a/admin/tool/lp/classes/external/exporter.php b/admin/tool/lp/classes/external/exporter.php new file mode 100644 index 00000000000..b9947df5690 --- /dev/null +++ b/admin/tool/lp/classes/external/exporter.php @@ -0,0 +1,428 @@ +. + +/** + * Generic exporter to take a stdClass and prepare it for return by webservice. + * + * @package tool_lp + * @copyright 2015 Damyon Wiese + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +namespace tool_lp\external; + +require_once($CFG->libdir . '/externallib.php'); + +use stdClass; +use renderer_base; +use context; +use context_system; +use coding_exception; +use external_single_structure; +use external_multiple_structure; +use external_value; +use external_format_value; + +/** + * Generic exporter to take a stdClass and prepare it for return by webservice. + * + * @copyright 2015 Damyon Wiese + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +abstract class exporter { + + /** @var array $related List of related objects used to avoid DB queries. */ + protected $related = array(); + + protected $data = null; + + /** + * Constructor - saves the persistent object, and the related objects. + * + * @param mixed $data - Either an stdClass or an array of values. + * @param array $related - An optional list of pre-loaded objects related to this object. + */ + public function __construct($data, $related = array()) { + $this->data = $data; + // Cache the valid related objects. + foreach (static::define_related() as $key => $classname) { + $isarray = false; + // Allow [] to mean an array of values. + if (substr($classname, -2) === '[]') { + $classname = substr($classname, 0, -2); + $isarray = true; + } + $missingdataerr = 'Exporter class is missing required related data: (' . get_called_class() . ') '; + if ($isarray) { + if (array_key_exists($key, $related) && is_array($related[$key])) { + foreach ($related[$key] as $index => $value) { + if (!$value instanceof $classname) { + throw new coding_exception($missingdataerr . $key . ' => ' . $classname . '[]'); + } + } + $this->related[$key] = $related[$key]; + } else { + throw new coding_exception($missingdataerr . $key . ' => ' . $classname . '[]'); + } + } else { + if ((array_key_exists($key, $related) && ($related[$key] instanceof $classname))) { + $this->related[$key] = $related[$key]; + } else { + throw new coding_exception($missingdataerr . $key . ' => ' . $classname); + } + } + } + } + + /** + * Function to export the renderer data in a format that is suitable for a + * mustache template. This means raw records are generated as in to_record, + * but all strings are correctly passed through external_format_text (or external_format_string). + * + * @param renderer_base $output Used to do a final render of any components that need to be rendered for export. + * @return stdClass + */ + final public function export(renderer_base $output) { + $data = new stdClass(); + $properties = self::properties_definition(true); + $context = $this->get_context(); + $values = (array) $this->data; + $values += $this->get_other_values($output); + $record = (object) $values; + + foreach ($properties as $property => $definition) { + if (isset($data->$property)) { + // This happens when we have already defined the format properties. + continue; + } else if (!property_exists($record, $property)) { + // Whoops, we got something that wasn't defined. + throw new coding_exception('Unexpected property ' . $property); + } + + $data->$property = $record->$property; + + // If the field is PARAM_TEXT and has a format field. + if ($propertyformat = self::get_format_field($properties, $property)) { + $format = $record->$propertyformat; + list($text, $format) = external_format_text($data->$property, $format, $context->id, 'tool_lp', '', 0); + $data->$property = $text; + $data->$propertyformat = $format; + + // If it's a PARAM_TEXT without format field. + } else if ($definition['type'] === PARAM_TEXT) { + $data->$property = external_format_string($data->$property, $context->id); + } + } + + return $data; + } + + /** + * Function to guess the correct context, falling back to system context. + * + * @return context + */ + 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(); + } + return $context; + } + + /** + * Get the additional values to inject while exporting. + * + * These are additional generated values that are not passed in through $data + * to the exporter. For a persistent exporter - these are generated values that + * do not exist in the persistent class. For your convenience the format_text or + * format_string functions do not need to be applied to PARAM_TEXT fields, + * it will be done automatically during export. + * + * These values are only used when returning data via {@link self::export()}, + * they are not used when generating any of the different external structures. + * + * Note: These must be defined in {@link self::define_other_properties()}. + * + * @return array Keys are the property names, values are their values. + */ + protected function get_other_values(renderer_base $output) { + return array(); + } + + /** + * Get the properties definition of this exporter. + * + * @param bool $additional Whether or not to include the additional properties. + * @return array Keys are the property names, and value their definition. + */ + final public static function properties_definition($additional = false) { + $properties = static::define_properties(); + if ($additional) { + $customprops = static::define_other_properties(); + foreach ($customprops as $property => $definition) { + // Ensures that null is set to its default. + if (!isset($definition['null'])) { + $customprops[$property]['null'] = NULL_NOT_ALLOWED; + } + } + $properties += $customprops; + } + return $properties; + } + + /** + * Return the list of additional properties used only for display. + * + * Additional properties are only ever used for the read structure, and during + * export of the persistent data. + * + * The format of the array returned by this method has to match the structure + * defined in {@link \tool_lp\persistent::define_properties()}. The display properties + * can however do some more fancy things. They can define 'multiple' => true to wrap + * values in an external_multiple_structure automatically - or they can define the + * type as a nested array of more properties in order to generate a nested + * external_single_structure. + * + * See {@link \tool_lp\external\competency_with_linked_courses_exporter} for an + * example returning a nested array of properties, defined by another exporter. + * + * @return array + */ + protected static function define_other_properties() { + return array(); + } + + /** + * Return the list of properties. + * + * The format of the array returned by this method has to match the structure + * defined in {@link \tool_lp\persistent::define_properties()}. + * + * @return array + */ + protected static function define_properties() { + return array(); + } + + /** + * Returns a list of objects that are related to this persistent. + * + * Only objects listed here can be cached in this object. + * + * @return array of 'propertyname' => array('type' => classname, 'required' => true) + */ + protected static function define_related() { + return array(); + } + + /** + * Get the context structure. + * + * @return external_single_structure + */ + final protected static function get_context_structure() { + return array( + 'contextid' => new external_value(PARAM_INT, 'The context id', VALUE_OPTIONAL), + 'contextlevel' => new external_value(PARAM_ALPHA, 'The context level', VALUE_OPTIONAL), + 'instanceid' => new external_value(PARAM_INT, 'The Instance id', VALUE_OPTIONAL), + ); + } + + /** + * Get the format field name. + * + * @param array $definitions List of properties definitions. + * @param string $property The name of the property that may have a format field. + * @return bool|string False, or the name of the format property. + */ + final protected static function get_format_field($definitions, $property) { + $formatproperty = $property . 'format'; + if ($definitions[$property]['type'] == PARAM_TEXT && isset($definitions[$formatproperty]) + && $definitions[$formatproperty]['type'] == PARAM_INT) { + return $formatproperty; + } + return false; + } + + /** + * Get the format structure. + * + * @param string $property The name of the property on which the format applies. + * @param array $definition The definition of the format property. + * @param int $required Constant VALUE_*. + * @return external_format_value + */ + final protected static function get_format_structure($property, $definition, $required = VALUE_REQUIRED) { + if (array_key_exists('default', $definition)) { + $required = VALUE_DEFAULT; + } + return new external_format_value($property, $required); + } + + /** + * Returns the create structure. + * + * @return external_single_structure + */ + final public static function get_create_structure() { + $properties = self::properties_definition(false); + $returns = array(); + + foreach ($properties as $property => $definition) { + if ($property == 'id') { + // The can not be set on create. + continue; + + } else if (isset($returns[$property]) && substr($property, -6) === 'format') { + // We've already treated the format. + continue; + } + + $required = VALUE_REQUIRED; + $default = null; + + // We cannot use isset here because we want to detect nulls. + if (array_key_exists('default', $definition)) { + $required = VALUE_DEFAULT; + $default = $definition['default']; + } + + // Magically treat the contextid fields. + if ($property == 'contextid') { + if (isset($properties['context'])) { + throw new coding_exception('There cannot be a context and a contextid column'); + } + $returns += self::get_context_structure(); + + } else { + $returns[$property] = new external_value($definition['type'], $property, $required, $default, $definition['null']); + + // Magically treat the format properties. + if ($formatproperty = self::get_format_field($properties, $property)) { + if (isset($returns[$formatproperty])) { + throw new coding_exception('The format for \'' . $property . '\' is already defined.'); + } + $returns[$formatproperty] = self::get_format_structure($property, + $properties[$formatproperty], VALUE_REQUIRED); + } + } + } + + return new external_single_structure($returns); + } + + /** + * Returns the read structure. + * + * @return external_single_structure + */ + final public static function get_read_structure() { + $properties = self::properties_definition(true); + + return self::get_read_structure_from_properties($properties); + } + + /** + * Returns the read structure from a set of properties (recursive). + * + * @return external_single_structure + */ + final protected static function get_read_structure_from_properties($properties) { + $returns = array(); + foreach ($properties as $property => $definition) { + if (isset($returns[$property]) && substr($property, -6) === 'format') { + // We've already treated the format. + continue; + } + $thisvalue = null; + + $type = $definition['type']; + if (is_array($type)) { + // This is a nested array of more properties. + $thisvalue = self::get_read_structure_from_properties($type); + } else { + if ($definition['type'] == PARAM_TEXT) { + // PARAM_TEXT always becomes PARAM_RAW because filters may be applied. + $type = PARAM_RAW; + } + $thisvalue = new external_value($type, $property); + } + if (!empty($definition['multiple'])) { + $returns[$property] = new external_multiple_structure($thisvalue); + } else { + $returns[$property] = $thisvalue; + + // Magically treat the format properties (not possible for arrays). + if ($formatproperty = self::get_format_field($properties, $property)) { + if (isset($returns[$formatproperty])) { + throw new coding_exception('The format for \'' . $property . '\' is already defined.'); + } + $returns[$formatproperty] = self::get_format_structure($property, $properties[$formatproperty]); + } + } + } + + return new external_single_structure($returns); + } + + /** + * Returns the update structure. + * + * @return external_single_structure + */ + final public static function get_update_structure() { + $properties = self::properties_definition(false); + $returns = array(); + + foreach ($properties as $property => $definition) { + if (isset($returns[$property]) && substr($property, -6) === 'format') { + // We've already treated the format. + continue; + } + + $default = null; + $required = VALUE_OPTIONAL; + if ($property == 'id') { + $required = VALUE_REQUIRED; + } + + // Magically treat the contextid fields. + if ($property == 'contextid') { + if (isset($properties['context'])) { + throw new coding_exception('There cannot be a context and a contextid column'); + } + $returns += self::get_context_structure(); + + } else { + $returns[$property] = new external_value($definition['type'], $property, $required, $default, $definition['null']); + + // Magically treat the format properties. + if ($formatproperty = self::get_format_field($properties, $property)) { + if (isset($returns[$formatproperty])) { + throw new coding_exception('The format for \'' . $property . '\' is already defined.'); + } + $returns[$formatproperty] = self::get_format_structure($property, + $properties[$formatproperty], VALUE_OPTIONAL); + } + } + } + + return new external_single_structure($returns); + } + +} diff --git a/admin/tool/lp/classes/external/persistent_exporter.php b/admin/tool/lp/classes/external/persistent_exporter.php index 17dbffa01ee..7bdc3811132 100644 --- a/admin/tool/lp/classes/external/persistent_exporter.php +++ b/admin/tool/lp/classes/external/persistent_exporter.php @@ -25,14 +25,7 @@ namespace tool_lp\external; require_once($CFG->libdir . '/externallib.php'); -use stdClass; -use renderer_base; -use context; -use context_system; use coding_exception; -use external_single_structure; -use external_value; -use external_format_value; /** * An extended version of the persistent class with a default implementation of export @@ -40,14 +33,11 @@ use external_format_value; * @copyright 2015 Damyon Wiese * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -abstract class persistent_exporter { +abstract class persistent_exporter extends exporter { /** @var \tool_lp\persistent The persistent object we will export. */ protected $persistent = null; - /** @var array $related List of related objects used to avoid DB queries. */ - protected $related = array(); - /** * Constructor - saves the persistent object, and the related objects. * @@ -62,112 +52,23 @@ abstract class persistent_exporter { } $this->persistent = $persistent; - // Cache the valid related objects. - foreach (static::define_related() as $key => $classname) { - if (isset($related[$key]) && ($related[$key] instanceof $classname)) { - $this->related[$key] = $related[$key]; - } else { - throw new coding_exception('Exporter class is missing required related data: ' . $key . ' => ' . $classname); - } - } - } - /** - * Function to export the renderer data in a format that is suitable for a - * mustache template. This means raw records are generated as in to_record, - * but all strings are correctly passed through external_format_text (or external_format_string). - * - * @param renderer_base $output Used to do a final render of any components that need to be rendered for export. - * @return stdClass - */ - final public function export(renderer_base $output) { - $data = new stdClass(); - $properties = self::properties_definition(true); - $context = $this->get_context(); - $values = (array) $this->persistent->to_record(); - $values += $this->get_values($output); - $record = (object) $values; - - foreach ($properties as $property => $definition) { - if (isset($data->$property)) { - // This happens when we have already defined the format properties. - continue; - } else if (!property_exists($record, $property)) { - // Whoops, we got something that wasn't defined. - throw new coding_exception('Unexpected property ' . $property); - } - - $data->$property = $record->$property; - - // If the field is PARAM_TEXT and has a format field. - if ($propertyformat = self::get_format_field($properties, $property)) { - $format = $record->$propertyformat; - list($text, $format) = external_format_text($data->$property, $format, $context->id, 'tool_lp', '', 0); - $data->$property = $text; - $data->$propertyformat = $format; - - // If it's a PARAM_TEXT without format field. - } else if ($definition['type'] === PARAM_TEXT) { - $data->$property = external_format_string($data->$property, $context->id); - } + if (method_exists($this->persistent, 'get_context') && !isset($this->related['context'])) { + $this->related['context'] = $this->persistent->get_context(); } - return $data; + $data = $persistent->to_record(); + parent::__construct($data, $related); } /** - * Function to guess the correct context, falling back to system context. + * Persistent exporters get their standard properties from the persistent class. * - * @return context - */ - final protected function get_context() { - $context = null; - if (isset($this->related['context']) && $this->related['context'] instanceof context) { - $context = $this->related['context']; - } else if (method_exists($this->persistent, 'get_context')) { - $context = $this->persistent->get_context(); - } else { - $context = context_system::instance(); - } - return $context; - } - - /** - * Get the additional values to inject while exporting. - * - * This should be overriden by child classes if needed. Existing persistent - * properties cannot be overridden. For your convenience the format_text or - * format_string functions do not need to be applied to PARAM_TEXT fields, - * it will be done automatically during export. - * - * Note: These must be defined in {@link self::define_properties()}. - * - * @return array Keys are the property names, values are their values. - */ - protected function get_values(renderer_base $output) { - return array(); - } - - /** - * Get the properties definition of this exporter. - * - * @param bool $additional Whether or not to include the additional properties. * @return array Keys are the property names, and value their definition. */ - final public static function properties_definition($additional = false) { + protected static function define_properties() { $classname = static::define_class(); - $properties = $classname::properties_definition(); - if ($additional) { - $customprops = static::define_properties(); - foreach ($customprops as $property => $definition) { - // Ensures that null is set to its default. - if (!isset($definition['null'])) { - $customprops[$property]['null'] = NULL_NOT_ALLOWED; - } - } - $properties += $customprops; - } - return $properties; + return $classname::properties_definition(); } /** @@ -179,205 +80,4 @@ abstract class persistent_exporter { throw new coding_exception('define_class() must be overidden.'); } - /** - * Return the list of additional properties. - * - * Additional properties are only ever used for the read structure, and during - * export of the persistent data. - * - * The format of the array returned by this method has to match the structure - * defined in {@link \tool_lp\persistent::define_properties()}. - * - * @return array - */ - protected static function define_properties() { - return array(); - } - - /** - * Returns a list of objects that are related to this persistent. - * - * Only objects listed here can be cached in this object. - * - * @return array of 'propertyname' => classname - */ - protected static function define_related() { - return array(); - } - - /** - * Get the context structure. - * - * @return external_single_structure - */ - final protected static function get_context_structure() { - return array( - 'contextid' => new external_value(PARAM_INT, 'The context id', VALUE_OPTIONAL), - 'contextlevel' => new external_value(PARAM_ALPHA, 'The context level', VALUE_OPTIONAL), - 'instanceid' => new external_value(PARAM_INT, 'The Instance id', VALUE_OPTIONAL), - ); - } - - /** - * Get the format field name. - * - * @param array $definitions List of properties definitions. - * @param string $property The name of the property that may have a format field. - * @return bool|string False, or the name of the format property. - */ - final protected static function get_format_field($definitions, $property) { - $formatproperty = $property . 'format'; - if ($definitions[$property]['type'] == PARAM_TEXT && isset($definitions[$formatproperty]) - && $definitions[$formatproperty]['type'] == PARAM_INT) { - return $formatproperty; - } - return false; - } - - /** - * Get the format structure. - * - * @param string $property The name of the property on which the format applies. - * @param array $definition The definition of the format property. - * @param int $required Constant VALUE_*. - * @return external_format_value - */ - final protected static function get_format_structure($property, $definition, $required = VALUE_REQUIRED) { - if (array_key_exists('default', $definition)) { - $required = VALUE_DEFAULT; - } - return new external_format_value($property, $required); - } - - /** - * Returns the create structure. - * - * @return external_single_structure - */ - final public static function get_create_structure() { - $properties = self::properties_definition(false); - $returns = array(); - - foreach ($properties as $property => $definition) { - if ($property == 'id') { - // The can not be set on create. - continue; - - } else if (isset($returns[$property]) && substr($property, -6) === 'format') { - // We've already treated the format. - continue; - } - - $required = VALUE_REQUIRED; - $default = null; - - // We cannot use isset here because we want to detect nulls. - if (array_key_exists('default', $definition)) { - $required = VALUE_DEFAULT; - $default = $definition['default']; - } - - // Magically treat the contextid fields. - if ($property == 'contextid') { - if (isset($properties['context'])) { - throw new coding_exception('There cannot be a context and a contextid column'); - } - $returns += self::get_context_structure(); - - } else { - $returns[$property] = new external_value($definition['type'], $property, $required, $default, $definition['null']); - - // Magically treat the format properties. - if ($formatproperty = self::get_format_field($properties, $property)) { - if (isset($returns[$formatproperty])) { - throw new coding_exception('The format for \'' . $property . '\' is already defined.'); - } - $returns[$formatproperty] = self::get_format_structure($property, - $properties[$formatproperty], VALUE_REQUIRED); - } - } - } - - return new external_single_structure($returns); - } - - /** - * Returns the read structure. - * - * @return external_single_structure - */ - final public static function get_read_structure() { - $properties = self::properties_definition(true); - $returns = array(); - - foreach ($properties as $property => $definition) { - if (isset($returns[$property]) && substr($property, -6) === 'format') { - // We've already treated the format. - continue; - } - - $type = $definition['type']; - if ($definition['type'] == PARAM_TEXT) { - // PARAM_TEXT always becomes PARAM_RAW because filters may be applied. - $type = PARAM_RAW; - } - $returns[$property] = new external_value($type, $property); - - // Magically treat the format properties. - if ($formatproperty = self::get_format_field($properties, $property)) { - if (isset($returns[$formatproperty])) { - throw new coding_exception('The format for \'' . $property . '\' is already defined.'); - } - $returns[$formatproperty] = self::get_format_structure($property, $properties[$formatproperty]); - } - } - - return new external_single_structure($returns); - } - - /** - * Returns the update structure. - * - * @return external_single_structure - */ - final public static function get_update_structure() { - $properties = self::properties_definition(false); - $returns = array(); - - foreach ($properties as $property => $definition) { - if (isset($returns[$property]) && substr($property, -6) === 'format') { - // We've already treated the format. - continue; - } - - $default = null; - $required = VALUE_OPTIONAL; - if ($property == 'id') { - $required = VALUE_REQUIRED; - } - - // Magically treat the contextid fields. - if ($property == 'contextid') { - if (isset($properties['context'])) { - throw new coding_exception('There cannot be a context and a contextid column'); - } - $returns += self::get_context_structure(); - - } else { - $returns[$property] = new external_value($definition['type'], $property, $required, $default, $definition['null']); - - // Magically treat the format properties. - if ($formatproperty = self::get_format_field($properties, $property)) { - if (isset($returns[$formatproperty])) { - throw new coding_exception('The format for \'' . $property . '\' is already defined.'); - } - $returns[$formatproperty] = self::get_format_structure($property, - $properties[$formatproperty], VALUE_OPTIONAL); - } - } - } - - return new external_single_structure($returns); - } - } diff --git a/admin/tool/lp/classes/external/plan_exporter.php b/admin/tool/lp/classes/external/plan_exporter.php index e23fd67cdee..d70dc3c4c96 100644 --- a/admin/tool/lp/classes/external/plan_exporter.php +++ b/admin/tool/lp/classes/external/plan_exporter.php @@ -37,7 +37,7 @@ class plan_exporter extends persistent_exporter { return 'tool_lp\\plan'; } - protected function get_values(renderer_base $output) { + protected function get_other_values(renderer_base $output) { $classname = static::define_class(); return array( 'statusname' => $this->persistent->get_statusname(), @@ -50,7 +50,7 @@ class plan_exporter extends persistent_exporter { ); } - public static function define_properties() { + public static function define_other_properties() { return array( 'statusname' => array( 'type' => PARAM_RAW, diff --git a/admin/tool/lp/classes/external/template_exporter.php b/admin/tool/lp/classes/external/template_exporter.php index bec09a4a6d2..9ee32da7e7f 100644 --- a/admin/tool/lp/classes/external/template_exporter.php +++ b/admin/tool/lp/classes/external/template_exporter.php @@ -39,7 +39,7 @@ class template_exporter extends persistent_exporter { return 'tool_lp\\template'; } - protected function get_values(renderer_base $output) { + protected function get_other_values(renderer_base $output) { return array( 'duedateformatted' => userdate($this->persistent->get_duedate()), 'cohortscount' => template_cohort::count_records(array('templateid' => $this->persistent->get_id())), @@ -47,7 +47,7 @@ class template_exporter extends persistent_exporter { ); } - protected static function define_properties() { + protected static function define_other_properties() { return array( 'duedateformatted' => array( 'type' => PARAM_RAW diff --git a/admin/tool/lp/classes/external/user_competency_exporter.php b/admin/tool/lp/classes/external/user_competency_exporter.php index be02e506b18..3ff7c83c2e5 100644 --- a/admin/tool/lp/classes/external/user_competency_exporter.php +++ b/admin/tool/lp/classes/external/user_competency_exporter.php @@ -44,7 +44,7 @@ class user_competency_exporter extends persistent_exporter { return array('scale' => 'grade_scale'); } - protected function get_values(renderer_base $output) { + protected function get_other_values(renderer_base $output) { $result = new stdClass(); if ($this->persistent->get_grade() === null) { @@ -70,7 +70,7 @@ class user_competency_exporter extends persistent_exporter { return (array) $result; } - protected static function define_properties() { + protected static function define_other_properties() { return array( 'gradename' => array( 'type' => PARAM_TEXT diff --git a/admin/tool/lp/classes/external/user_competency_plan_exporter.php b/admin/tool/lp/classes/external/user_competency_plan_exporter.php index 6f948044bc0..17b799203bf 100644 --- a/admin/tool/lp/classes/external/user_competency_plan_exporter.php +++ b/admin/tool/lp/classes/external/user_competency_plan_exporter.php @@ -43,7 +43,7 @@ class user_competency_plan_exporter extends persistent_exporter { return array('scale' => 'grade_scale'); } - protected function get_values(renderer_base $output) { + protected function get_other_values(renderer_base $output) { $result = new stdClass(); if ($this->persistent->get_grade() === null) { @@ -63,7 +63,7 @@ class user_competency_plan_exporter extends persistent_exporter { return (array) $result; } - protected static function define_properties() { + protected static function define_other_properties() { return array( 'gradename' => array( 'type' => PARAM_TEXT diff --git a/admin/tool/lp/classes/output/template_competencies_page.php b/admin/tool/lp/classes/output/template_competencies_page.php index aa96d81e3cd..15e15d47cff 100644 --- a/admin/tool/lp/classes/output/template_competencies_page.php +++ b/admin/tool/lp/classes/output/template_competencies_page.php @@ -27,12 +27,11 @@ use renderable; use templatable; use renderer_base; use stdClass; -use moodle_url; use context; use context_system; -use context_course; +use moodle_url; use tool_lp\api; -use tool_lp\external\competency_exporter; +use tool_lp\external\competency_with_linked_courses_exporter; /** * Class containing data for learning plan template competencies page @@ -93,16 +92,11 @@ class template_competencies_page implements renderable, templatable { } $context = $contextcache[$competency->get_competencyframeworkid()]; - $exporter = new competency_exporter($competency, array('context' => $context)); - $record = $exporter->export($output); $courses = api::list_courses_using_competency($competency->get_id()); - foreach ($courses as $course) { - $coursecontext = context_course::instance($course->id); - $course->fullname = external_format_string($course->fullname, $coursecontext->id); - $course->shortname = external_format_string($course->shortname, $coursecontext->id); - } - $record->linkedcourses = $courses; - $record->hascourses = count($courses) > 0; + $related = array('competency' => $competency, 'linkedcourses' => $courses, 'context' => $context); + $exporter = new competency_with_linked_courses_exporter(null, $related); + $record = $exporter->export($output); + array_push($data->competencies, $record); } $data->canmanagecompetencyframeworks = $this->canmanagecompetencyframeworks; diff --git a/admin/tool/lp/templates/template_competencies_page.mustache b/admin/tool/lp/templates/template_competencies_page.mustache index 3d49149333d..8226bd25a36 100644 --- a/admin/tool/lp/templates/template_competencies_page.mustache +++ b/admin/tool/lp/templates/template_competencies_page.mustache @@ -22,15 +22,17 @@
{{#competencies}} -
+
{{#canmanagetemplatecompetencies}} {{/canmanagetemplatecompetencies}} + {{#competency}} {{> tool_lp/competency_summary }} + {{/competency}} {{#str}}linkedcourses, tool_lp{{/str}} {{#hascourses}}