From 1d8f0a6f50f00a9c9bd211e02a294b3f1a79d14a Mon Sep 17 00:00:00 2001 From: Frederic Massart Date: Fri, 30 Oct 2015 11:49:30 +0800 Subject: [PATCH] MDL-51034 tool_lp: List competencies in a user's plan --- admin/tool/lp/classes/api.php | 46 +++++++ .../tool/lp/classes/competency_framework.php | 13 ++ admin/tool/lp/classes/external.php | 107 ++++++++++++++++ admin/tool/lp/classes/output/plan_page.php | 114 ++++++++++++++++++ admin/tool/lp/classes/output/renderer.php | 11 ++ admin/tool/lp/classes/persistent.php | 4 +- admin/tool/lp/classes/plan.php | 27 +++++ admin/tool/lp/classes/template_competency.php | 5 +- admin/tool/lp/classes/user_competency.php | 48 ++++++++ admin/tool/lp/db/services.php | 9 ++ admin/tool/lp/lang/en/tool_lp.php | 7 +- admin/tool/lp/plan.php | 52 ++++++++ admin/tool/lp/templates/plan_page.mustache | 53 ++++++++ 13 files changed, 489 insertions(+), 7 deletions(-) create mode 100644 admin/tool/lp/classes/output/plan_page.php create mode 100644 admin/tool/lp/plan.php create mode 100644 admin/tool/lp/templates/plan_page.mustache diff --git a/admin/tool/lp/classes/api.php b/admin/tool/lp/classes/api.php index 1f2f77be4e2..1f817df628e 100644 --- a/admin/tool/lp/classes/api.php +++ b/admin/tool/lp/classes/api.php @@ -1306,6 +1306,52 @@ class api { return $plan->delete(); } + /** + * List the competencies in a user plan. + * + * @param int $planorid The plan, or its ID. + * @return array((object) array('competency' => competency, 'usercompetency' => user_competency)) + */ + public static function list_plan_competencies($planorid) { + $plan = $planorid; + if (!is_object($planorid)) { + $plan = new plan($planorid); + } + + if (!$plan->can_read()) { + $context = context_user::instance($plan->get_userid()); + throw new required_capability_exception($context, 'tool/lp:planview', 'nopermissions', ''); + } + + $result = array(); + $competencies = $plan->get_competencies(); + $usercompetencies = user_competency::get_multiple($plan->get_userid(), $competencies); + + // Build the return values. + foreach ($competencies as $key => $competency) { + $found = false; + + foreach ($usercompetencies as $uckey => $uc) { + if ($uc->get_competencyid() == $competency->get_id()) { + $found = true; + unset($usercompetencies[$uckey]); + break; + } + } + + if (!$found) { + $uc = user_competency::create_relation($plan->get_userid(), $competency->get_id()); + } + + $result[] = (object) array( + 'competency' => $competency, + 'usercompetency' => $uc, + ); + } + + return $result; + } + /** * List all the related competencies. * diff --git a/admin/tool/lp/classes/competency_framework.php b/admin/tool/lp/classes/competency_framework.php index 79ab66972e9..844390b567b 100644 --- a/admin/tool/lp/classes/competency_framework.php +++ b/admin/tool/lp/classes/competency_framework.php @@ -27,6 +27,8 @@ use context; use lang_string; use stdClass; +require_once($CFG->libdir . '/grade/grade_scale.php'); + /** * Class for loading/storing competency frameworks from the DB. * @@ -111,6 +113,17 @@ class competency_framework extends persistent { ); } + /** + * Return the scale. + * + * @return \grade_scale + */ + public function get_scale() { + $scale = \grade_scale::fetch(array('id' => $this->get_scaleid())); + $scale->load_items(); + return $scale; + } + /** * Get the constant name for a level. * diff --git a/admin/tool/lp/classes/external.php b/admin/tool/lp/classes/external.php index 69651c48fd1..4ec68a91972 100644 --- a/admin/tool/lp/classes/external.php +++ b/admin/tool/lp/classes/external.php @@ -865,6 +865,69 @@ class external extends external_api { return new external_single_structure($returns); } + /** + * Returns the external structure of a full user_competency record. + * + * @return \external_single_structure + */ + protected static function get_user_competency_external_structure() { + $id = new external_value( + PARAM_INT, + 'Database record id' + ); + $userid = new external_value( + PARAM_INT, + 'User to whom this record belongs to' + ); + $competencyid = new external_value( + PARAM_INT, + 'The competency associated with this record' + ); + $status = new external_value( + PARAM_INT, + 'The status of the user competency' + ); + $reviewerid = new external_value( + PARAM_INT, + 'The reviewer ID' + ); + $proficiency = new external_value( + PARAM_BOOL, + 'Whether or not the user is proficient' + ); + $grade = new external_value( + PARAM_INT, + 'The scale grade' + ); + $timecreated = new external_value( + PARAM_INT, + 'Timestamp this record was created' + ); + $timemodified = new external_value( + PARAM_INT, + 'Timestamp this record was modified' + ); + $usermodified = new external_value( + PARAM_INT, + 'User who modified this record last' + ); + + $returns = array( + 'id' => $id, + 'userid' => $userid, + 'competencyid' => $competencyid, + 'status' => $status, + 'reviewerid' => $reviewerid, + 'proficiency' => $proficiency, + 'grade' => $grade, + 'timecreated' => $timecreated, + 'timemodified' => $timemodified, + 'usermodified' => $usermodified, + ); + + return new external_single_structure($returns); + } + /** * Returns description of create_competency() parameters. * @@ -3356,6 +3419,50 @@ class external extends external_api { )); } + /** + * External function parameters structure. + * + * @return \external_description + */ + public static function list_plan_competencies_parameters() { + return new external_single_structure(array( + 'id' => new external_value(PARAM_INT, 'The plan ID.') + )); + } + + /** + * List plan competencies. + * @param int $id The plan ID. + * @return array + */ + public static function list_plan_competencies($id) { + $params = self::validate_parameters(self::list_plan_competencies_parameters(), array('id' => $id)); + $id = $params['id']; + $plan = api::read_plan($id); + $result = api::list_plan_competencies($plan); + foreach ($result as $key => $r) { + $r->competency = $r->competency->to_record(); + $r->competency->descriptionformatted = format_text($r->competency->description, + $r->competency->descriptionformat, array('context' => $plan->get_context())); + $r->usercompetency = $r->usercompetency->to_record(); + } + return $result; + } + + /** + * External function return structure. + * + * @return \external_description + */ + public static function list_plan_competencies_returns() { + return new external_multiple_structure( + new external_single_structure(array( + 'competency' => self::get_competency_external_structure(), + 'usercompetency' => self::get_user_competency_external_structure(), + ) + )); + } + /** * Returns the description of the get_scale_values() parameters. * diff --git a/admin/tool/lp/classes/output/plan_page.php b/admin/tool/lp/classes/output/plan_page.php new file mode 100644 index 00000000000..cf1f3154b0c --- /dev/null +++ b/admin/tool/lp/classes/output/plan_page.php @@ -0,0 +1,114 @@ +. + +/** + * Plan page output. + * + * @package tool_lp + * @copyright 2015 Frédéric Massart - FMCorz.net + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +namespace tool_lp\output; + +use renderable; +use templatable; +use stdClass; +use tool_lp\api; +use tool_lp\user_competency; +use context_user; + +/** + * Plan page class. + * + * @package tool_lp + * @copyright 2015 Frédéric Massart - FMCorz.net + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class plan_page implements renderable, templatable { + + /** @var plan */ + protected $plan; + + /** + * Construct. + * + * @param plan $plan + */ + public function __construct($plan) { + $this->plan = $plan; + } + + /** + * Export the data. + * + * @param renderer_base $output + * @return stdClass + */ + public function export_for_template(\renderer_base $output) { + $options = array('context' => $this->plan->get_context()); + $frameworks = array(); + $scales = array(); + + $data = new stdClass(); + $data->competencies = array(); + + $pclist = api::list_plan_competencies($this->plan); + foreach ($pclist as $pc) { + $comp = $pc->competency; + $usercomp = $pc->usercompetency; + + if (!isset($frameworks[$comp->get_competencyframeworkid()])) { + $frameworks[$comp->get_competencyframeworkid()] = $comp->get_framework(); + } + $framework = $frameworks[$comp->get_competencyframeworkid()]; + if (!isset($scales[$framework->get_scaleid()])) { + $scales[$framework->get_scaleid()] = $framework->get_scale(); + } + $scale = $scales[$framework->get_scaleid()]; + + // Prepare the data. + $competency = $comp->to_record(); + $competency->descriptionformatted = format_text($competency->description, $competency->descriptionformat, $options); + $usercompetency = $usercomp->to_record(); + $competency->usercompetency = $usercompetency; + + if ($usercompetency->grade === null) { + $gradename = '-'; + } else { + $gradename = format_string($scale->scale_items[$usercompetency->grade - 1], null, $options); + } + + if ($usercompetency->proficiency === null) { + $proficiencyname = '-'; + } else { + $proficiencyname = get_string($usercompetency->proficiency ? 'yes' : 'no'); + } + + $statusname = '-'; + if ($usercompetency->status != user_competency::STATUS_IDLE) { + $statusname = (string) user_competency::get_status_name($usercompetency->status); + } + + $usercompetency->gradename = $gradename; + $usercompetency->proficiencyname = $proficiencyname; + $usercompetency->statusname = $statusname; + + $data->competencies[] = $competency; + } + + return $data; + } +} diff --git a/admin/tool/lp/classes/output/renderer.php b/admin/tool/lp/classes/output/renderer.php index 6b6d1944e9a..a06514c632b 100644 --- a/admin/tool/lp/classes/output/renderer.php +++ b/admin/tool/lp/classes/output/renderer.php @@ -98,6 +98,17 @@ class renderer extends plugin_renderer_base { return parent::render_from_template('tool_lp/manage_templates_page', $data); } + /** + * Defer to template. + * + * @param plan_page $page + * @return bool|string + */ + public function render_plan_page(plan_page $page) { + $data = $page->export_for_template($this); + return parent::render_from_template('tool_lp/plan_page', $data); + } + /** * Defer to template. * diff --git a/admin/tool/lp/classes/persistent.php b/admin/tool/lp/classes/persistent.php index fbd27618827..1c5ad2207c8 100644 --- a/admin/tool/lp/classes/persistent.php +++ b/admin/tool/lp/classes/persistent.php @@ -629,7 +629,7 @@ abstract class persistent { * @param int $skip Limitstart. * @param int $limit Number of rows to return. * - * @return persistent[] + * @return \tool_lp\persistent[] */ public static function get_records($filters = array(), $sort = '', $order = 'ASC', $skip = 0, $limit = 0) { global $DB; @@ -658,7 +658,7 @@ abstract class persistent { * @param string $fields * @param int $limitfrom * @param int $limitnum - * @return \tool_lp\plan[] + * @return \tool_lp\persistent[] */ public static function get_records_select($select, $params = null, $sort = '', $fields = '*', $limitfrom = 0, $limitnum = 0) { global $DB; diff --git a/admin/tool/lp/classes/plan.php b/admin/tool/lp/classes/plan.php index d130608cb76..767b10aa0c2 100644 --- a/admin/tool/lp/classes/plan.php +++ b/admin/tool/lp/classes/plan.php @@ -109,6 +109,33 @@ class plan extends persistent { return self::can_read_user($this->get_userid()); } + /** + * Get the competencies in this plan. + * + * @return competency[] + */ + public function get_competencies() { + $competencies = array(); + if ($this->get_templateid()) { + // Get the competencies from the template. + $competencies = template_competency::list_competencies($this->get_templateid(), true); + } else { + // TODO MDL-50328. + // Get the competencies in this plan. + // $competencies = plan_competency::list_competencies($this->get_id()); + } + return $competencies; + } + + /** + * Get the context in which the plan is attached. + * + * @return context_user + */ + public function get_context() { + return context_user::instance($this->get_userid()); + } + /** * Human readable status name. * diff --git a/admin/tool/lp/classes/template_competency.php b/admin/tool/lp/classes/template_competency.php index 2b9a53a7726..7aeeb10c04d 100644 --- a/admin/tool/lp/classes/template_competency.php +++ b/admin/tool/lp/classes/template_competency.php @@ -157,8 +157,7 @@ class template_competency extends persistent { FROM {' . competency::TABLE . '} comp JOIN {' . self::TABLE . '} tplcomp ON tplcomp.competencyid = comp.id - WHERE tplcomp.templateid = ? - ORDER BY tplcomp.sortorder ASC'; + WHERE tplcomp.templateid = ?'; $params = array($templateid); if ($onlyvisible) { @@ -166,6 +165,8 @@ class template_competency extends persistent { $params[] = 1; } + $sql .= 'ORDER BY tplcomp.sortorder ASC'; + $results = $DB->get_records_sql($sql, $params); $instances = array(); diff --git a/admin/tool/lp/classes/user_competency.php b/admin/tool/lp/classes/user_competency.php index 574f79db697..0f260047345 100644 --- a/admin/tool/lp/classes/user_competency.php +++ b/admin/tool/lp/classes/user_competency.php @@ -190,4 +190,52 @@ class user_competency extends persistent { return true; } + /** + * Create a new user_competency object. + * + * Note, this is intended to be used to create a blank relation, for instance when + * the record was not found in the database. This does not save the model. + * + * @param int $userid The user ID. + * @param int $competencyid The competency ID. + * @return \tool_lp\user_competency + */ + public static function create_relation($userid, $competencyid) { + $relation = new user_competency(0, (object) array('userid' => $userid, 'competencyid' => $competencyid)); + return $relation; + } + + /** + * Get multiple user_competency for a user. + * + * @param int $userid + * @param array $competenciesorids Limit search to those competencies, or competency IDs. + * @return \tool_lp\user_competency[] + */ + public static function get_multiple($userid, array $competenciesorids = null) { + global $DB; + + $params = array(); + $params['userid'] = $userid; + $sql = '1 = 1'; + + if (!empty($competenciesorids)) { + $test = reset($competenciesorids); + if (is_int($test)) { + $ids = $competenciesorids; + } else { + $ids = array(); + foreach ($competenciesorids as $comp) { + $ids[] = $comp->get_id(); + } + } + + list($insql, $inparams) = $DB->get_in_or_equal($ids, SQL_PARAMS_NAMED); + $params += $inparams; + $sql = "competencyid $insql"; + } + + return parent::get_records_select("userid = :userid AND $sql", $params); + } + } diff --git a/admin/tool/lp/db/services.php b/admin/tool/lp/db/services.php index 814c04ce30f..16482961555 100644 --- a/admin/tool/lp/db/services.php +++ b/admin/tool/lp/db/services.php @@ -424,6 +424,15 @@ $functions = array( 'capabilities' => 'tool/lp:planviewown', 'ajax' => true, ), + 'tool_lp_list_plan_competencies' => array( + 'classname' => 'tool_lp\external', + 'methodname' => 'list_plan_competencies', + 'classpath' => '', + 'description' => 'List the competencies in a plan', + 'type' => 'read', + 'capabilities' => 'tool/lp:planviewown', + 'ajax' => true, + ), 'tool_lp_get_scale_values' => array( 'classname' => 'tool_lp\external', 'methodname' => 'get_scale_values', diff --git a/admin/tool/lp/lang/en/tool_lp.php b/admin/tool/lp/lang/en/tool_lp.php index 45b7524c6b5..08af2fea377 100644 --- a/admin/tool/lp/lang/en/tool_lp.php +++ b/admin/tool/lp/lang/en/tool_lp.php @@ -39,9 +39,6 @@ $string['competencyframeworks'] = 'Competency Frameworks'; $string['competencyframeworkupdated'] = 'Competency framework updated.'; $string['competencypicker'] = 'Competency picker'; $string['competencyrelatedcompetencies'] = '{$a} related competencies'; -$string['usercompetencystatus_idle'] = 'Idle'; -$string['usercompetencystatus_inreview'] = 'In review'; -$string['usercompetencystatus_waitingforreview'] = 'Waiting for review'; $string['competencyupdated'] = 'Competency updated'; $string['configurescale'] = 'Configure scales'; $string['coursecompetencies'] = 'Course competencies'; @@ -134,6 +131,7 @@ $string['search'] = 'Search...'; $string['selectcompetencymovetarget'] = 'Select a location to move this competency to:'; $string['selectedcompetency'] = 'Selected competency'; $string['shortname'] = 'Name'; +$string['state'] = 'State'; $string['status'] = 'Status'; $string['taxonomies'] = 'Taxonomies'; $string['taxonomy_add_behaviour'] = 'Add behaviour'; @@ -196,5 +194,8 @@ $string['templatecreated'] = 'Learning plan template created'; $string['templatename'] = 'Name'; $string['templates'] = 'Learning plan templates'; $string['templateupdated'] = 'Learning plan template updated'; +$string['usercompetencystatus_idle'] = 'Idle'; +$string['usercompetencystatus_inreview'] = 'In review'; +$string['usercompetencystatus_waitingforreview'] = 'Waiting for review'; $string['visible'] = 'Visible'; $string['visible_help'] = 'A competency framework can be hidden from teachers. This could be useful if a framework is still in the process of being developed.'; diff --git a/admin/tool/lp/plan.php b/admin/tool/lp/plan.php new file mode 100644 index 00000000000..365d2967e95 --- /dev/null +++ b/admin/tool/lp/plan.php @@ -0,0 +1,52 @@ +. + +/** + * Plan page. + * + * @package tool_lp + * @copyright 2015 Frédéric Massart - FMCorz.net + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +require(__DIR__ . '/../../../config.php'); + +$id = required_param('id', PARAM_INT); + +require_login(null, false); +if (isguestuser()) { + throw new require_login_exception('Guests are not allowed here.'); +} + +$plan = \tool_lp\api::read_plan($id); +$context = $plan->get_context(); + +$url = new moodle_url('/admin/tool/lp/plan.php', array('id' => $id)); +$title = format_string($plan->get_name(), true, array('context' => $context)); +$PAGE->set_context($context); +$PAGE->set_pagelayout('admin'); +$PAGE->set_url($url); +$PAGE->set_title($title); +$PAGE->set_heading($title); + +$output = $PAGE->get_renderer('tool_lp'); +echo $output->header(); +echo $output->heading($title); + +$page = new \tool_lp\output\plan_page($plan); +echo $output->render($page); + +echo $output->footer(); diff --git a/admin/tool/lp/templates/plan_page.mustache b/admin/tool/lp/templates/plan_page.mustache new file mode 100644 index 00000000000..e552e47fdd4 --- /dev/null +++ b/admin/tool/lp/templates/plan_page.mustache @@ -0,0 +1,53 @@ +{{! + 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 . +}} +{{! + Plan page template. +}} +
+ + + + + + + + + + + + + {{#competencies}} + + + + + + + + {{/competencies}} + +
{{#str}}shortname, tool_lp{{/str}}{{#str}}status, tool_lp{{/str}}{{#str}}proficient, tool_lp{{/str}}{{#str}}state, tool_lp{{/str}}{{#str}}actions, tool_lp{{/str}}
{{shortname}}{{usercompetency.gradename}}{{usercompetency.proficiencyname}}{{usercompetency.statusname}}
+ +
+
+ +
+
+ +
+{{#js}} +{{/js}}