MDL-51041 cbe: Refactor to allow non-persistent exporters
This commit is contained in:
committed by
Frederic Massart
parent
cc8348db07
commit
d04ea1665e
@@ -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.'),
|
||||
));
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* 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,
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
+428
@@ -0,0 +1,428 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
}
|
||||
+8
-308
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -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,
|
||||
|
||||
+2
-2
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -22,15 +22,17 @@
|
||||
<div class="managecompetencies">
|
||||
<div class="drag-parentnode">
|
||||
{{#competencies}}
|
||||
<div class="drag-samenode" data-id="{{id}}">
|
||||
<div class="drag-samenode" data-id="{{competency.id}}">
|
||||
<div class="well">
|
||||
{{#canmanagetemplatecompetencies}}
|
||||
<span class="drag-handlecontainer pull-left"></span>
|
||||
<div class="pull-right">
|
||||
<a href="#" data-action="delete-competency-link" data-id="{{id}}">{{#pix}}t/delete, core, {{#str}}delete{{/str}}{{/pix}}</a>
|
||||
<a href="#" data-action="delete-competency-link" data-id="{{competency.id}}">{{#pix}}t/delete, core, {{#str}}delete{{/str}}{{/pix}}</a>
|
||||
</div>
|
||||
{{/canmanagetemplatecompetencies}}
|
||||
{{#competency}}
|
||||
{{> tool_lp/competency_summary }}
|
||||
{{/competency}}
|
||||
<strong>{{#str}}linkedcourses, tool_lp{{/str}}</strong>
|
||||
{{#hascourses}}
|
||||
<ul class="inline">
|
||||
|
||||
Reference in New Issue
Block a user