From 476bf96f4dccd6a5255cfe7c4bda080b00f20e6b Mon Sep 17 00:00:00 2001 From: Frederic Massart Date: Thu, 8 Dec 2016 17:11:12 +0800 Subject: [PATCH] MDL-57273 core: Added a performance helper to use with exporters --- .../course_competency_statistics_exporter.php | 8 +- .../external/template_statistics_exporter.php | 8 +- .../user_evidence_summary_exporter.php | 24 +-- .../output/competency_plan_navigation.php | 11 +- .../output/course_competencies_page.php | 12 +- admin/tool/lp/classes/output/plan_page.php | 29 +--- .../output/template_competencies_page.php | 14 +- .../user_competency_course_navigation.php | 14 +- competency/classes/external.php | 31 +--- .../classes/external/performance_helper.php | 111 ++++++++++++ .../external/user_evidence_exporter.php | 8 +- competency/tests/generator/lib.php | 74 +++++--- competency/tests/performance_helper_test.php | 159 ++++++++++++++++++ report/competency/classes/output/report.php | 24 +-- 14 files changed, 371 insertions(+), 156 deletions(-) create mode 100644 competency/classes/external/performance_helper.php create mode 100644 competency/tests/performance_helper_test.php diff --git a/admin/tool/lp/classes/external/course_competency_statistics_exporter.php b/admin/tool/lp/classes/external/course_competency_statistics_exporter.php index abe0154c548..15924d24982 100644 --- a/admin/tool/lp/classes/external/course_competency_statistics_exporter.php +++ b/admin/tool/lp/classes/external/course_competency_statistics_exporter.php @@ -27,6 +27,7 @@ defined('MOODLE_INTERNAL') || die(); use renderer_base; use moodle_url; use core_competency\external\competency_exporter; +use core_competency\external\performance_helper; /** * Class for exporting a course competency statistics summary. @@ -84,12 +85,9 @@ class course_competency_statistics_exporter extends \core\external\exporter { $proficientcompetencypercentageformatted = format_float($proficientcompetencypercentage); } $competencies = array(); - $contextcache = array(); + $helper = new performance_helper(); foreach ($this->data->leastproficientcompetencies as $competency) { - if (!isset($contextcache[$competency->get_competencyframeworkid()])) { - $contextcache[$competency->get_competencyframeworkid()] = $competency->get_context(); - } - $context = $contextcache[$competency->get_competencyframeworkid()]; + $context = $helper->get_context_from_competency($competency); $exporter = new competency_exporter($competency, array('context' => $context)); $competencies[] = $exporter->export($output); } diff --git a/admin/tool/lp/classes/external/template_statistics_exporter.php b/admin/tool/lp/classes/external/template_statistics_exporter.php index 7681a6dadb6..3ec92ac4da2 100644 --- a/admin/tool/lp/classes/external/template_statistics_exporter.php +++ b/admin/tool/lp/classes/external/template_statistics_exporter.php @@ -27,6 +27,7 @@ defined('MOODLE_INTERNAL') || die(); use renderer_base; use moodle_url; use core_competency\external\competency_exporter; +use core_competency\external\performance_helper; /** * Class for exporting a cohort summary from an stdClass. @@ -118,12 +119,9 @@ class template_statistics_exporter extends \core\external\exporter { $proficientusercompetencyplanpercentageformatted = format_float($proficientusercompetencyplanpercentage); } $competencies = array(); - $contextcache = array(); + $helper = new performance_helper(); foreach ($this->data->leastproficientcompetencies as $competency) { - if (!isset($contextcache[$competency->get_competencyframeworkid()])) { - $contextcache[$competency->get_competencyframeworkid()] = $competency->get_context(); - } - $context = $contextcache[$competency->get_competencyframeworkid()]; + $context = $helper->get_context_from_competency($competency); $exporter = new competency_exporter($competency, array('context' => $context)); $competencies[] = $exporter->export($output); } diff --git a/admin/tool/lp/classes/external/user_evidence_summary_exporter.php b/admin/tool/lp/classes/external/user_evidence_summary_exporter.php index 24309379cca..2db93d1e54e 100644 --- a/admin/tool/lp/classes/external/user_evidence_summary_exporter.php +++ b/admin/tool/lp/classes/external/user_evidence_summary_exporter.php @@ -27,6 +27,7 @@ defined('MOODLE_INTERNAL') || die(); use moodle_url; use renderer_base; use core_competency\external\stored_file_exporter; +use core_competency\external\performance_helper; /** * Class for exporting user evidence with all competencies. @@ -91,32 +92,19 @@ class user_evidence_summary_exporter extends \core\external\persistent_exporter } $userevidencecompetencies = array(); - $frameworks = array(); - $scales = array(); $usercompetencies = $this->persistent->get_user_competencies(); + $helper = new performance_helper(); foreach ($usercompetencies as $usercompetency) { $competency = $usercompetency->get_competency(); - // Get the framework. - if (!isset($frameworks[$competency->get_competencyframeworkid()])) { - $frameworks[$competency->get_competencyframeworkid()] = $competency->get_framework(); - } - $framework = $frameworks[$competency->get_competencyframeworkid()]; - - // Get the scale. - $scaleid = $competency->get_scaleid(); - if ($scaleid === null) { - $scaleid = $framework->get_scaleid(); - } - if (!isset($scales[$framework->get_scaleid()])) { - $scales[$framework->get_scaleid()] = $framework->get_scale(); - } - $scale = $scales[$framework->get_scaleid()]; + $context = $helper->get_context_from_competency($competency); + $framework = $helper->get_framework_from_competency($competency); + $scale = $helper->get_scale_from_competency($competency); $related = array('competency' => $competency, 'usercompetency' => $usercompetency, 'scale' => $scale, - 'context' => $framework->get_context()); + 'context' => $context); $userevidencecompetencysummaryexporter = new user_evidence_competency_summary_exporter(null, $related); diff --git a/admin/tool/lp/classes/output/competency_plan_navigation.php b/admin/tool/lp/classes/output/competency_plan_navigation.php index 58ab38bfc9f..4ff24720661 100644 --- a/admin/tool/lp/classes/output/competency_plan_navigation.php +++ b/admin/tool/lp/classes/output/competency_plan_navigation.php @@ -27,7 +27,8 @@ use renderable; use renderer_base; use templatable; use context_course; -use \core_competency\external\competency_exporter; +use core_competency\external\competency_exporter; +use core_competency\external\performance_helper; use stdClass; /** @@ -82,13 +83,9 @@ class competency_plan_navigation implements renderable, templatable { $plancompetencies = \core_competency\api::list_plan_competencies($data->planid); $data->competencies = array(); - $contextcache = array(); + $helper = new performance_helper(); foreach ($plancompetencies as $plancompetency) { - $frameworkid = $plancompetency->competency->get_competencyframeworkid(); - if (!isset($contextcache[$frameworkid])) { - $contextcache[$frameworkid] = $plancompetency->competency->get_context(); - } - $context = $contextcache[$frameworkid]; + $context = $helper->get_context_from_competency($plancompetency->competency); $exporter = new competency_exporter($plancompetency->competency, array('context' => $context)); $competency = $exporter->export($output); if ($competency->id == $this->competencyid) { diff --git a/admin/tool/lp/classes/output/course_competencies_page.php b/admin/tool/lp/classes/output/course_competencies_page.php index 395561f625b..a428c394c3d 100644 --- a/admin/tool/lp/classes/output/course_competencies_page.php +++ b/admin/tool/lp/classes/output/course_competencies_page.php @@ -35,6 +35,7 @@ use core_competency\api; use tool_lp\course_competency_statistics; use core_competency\competency; use core_competency\course_competency; +use core_competency\external\performance_helper; use core_competency\external\competency_exporter; use core_competency\external\course_competency_exporter; use core_competency\external\course_competency_settings_exporter; @@ -112,7 +113,6 @@ class course_competencies_page implements renderable, templatable { $data->courseid = $this->courseid; $data->pagecontextid = $this->context->id; $data->competencies = array(); - $contextcache = array(); $gradable = is_enrolled($this->context, $USER, 'moodle/competency:coursecompetencygradable'); if ($gradable) { @@ -126,13 +126,11 @@ class course_competencies_page implements renderable, templatable { $ruleoutcomeoptions[$value] = array('value' => $value, 'text' => (string) $text, 'selected' => false); } + $helper = new performance_helper(); foreach ($this->coursecompetencylist as $coursecompetencyelement) { $coursecompetency = $coursecompetencyelement['coursecompetency']; $competency = $coursecompetencyelement['competency']; - if (!isset($contextcache[$competency->get_competencyframeworkid()])) { - $contextcache[$competency->get_competencyframeworkid()] = $competency->get_context(); - } - $context = $contextcache[$competency->get_competencyframeworkid()]; + $context = $helper->get_context_from_competency($competency); $compexporter = new competency_exporter($competency, array('context' => $context)); $ccexporter = new course_competency_exporter($coursecompetency, array('context' => $context)); @@ -152,7 +150,7 @@ class course_competencies_page implements renderable, templatable { // Competency path. $pathexporter = new competency_path_exporter([ 'ancestors' => $competency->get_ancestors(), - 'framework' => $competency->get_framework(), + 'framework' => $helper->get_framework_from_competency($competency), 'context' => $context ]); @@ -172,7 +170,7 @@ class course_competencies_page implements renderable, templatable { } if ($foundusercompetencycourse) { $related = array( - 'scale' => $competency->get_scale() + 'scale' => $helper->get_scale_from_competency($competency) ); $exporter = new user_competency_course_exporter($foundusercompetencycourse, $related); $onerow['usercompetencycourse'] = $exporter->export($output); diff --git a/admin/tool/lp/classes/output/plan_page.php b/admin/tool/lp/classes/output/plan_page.php index f490f3b959c..aa79b83f802 100644 --- a/admin/tool/lp/classes/output/plan_page.php +++ b/admin/tool/lp/classes/output/plan_page.php @@ -29,6 +29,7 @@ use templatable; use stdClass; use moodle_url; use core_competency\api; +use core_competency\external\performance_helper; use core_competency\plan; use core_competency\external\competency_exporter; use core_competency\external\plan_exporter; @@ -62,9 +63,6 @@ class plan_page implements renderable, templatable { * @return stdClass */ public function export_for_template(\renderer_base $output) { - $frameworks = array(); - $scales = array(); - $planexporter = new plan_exporter($this->plan, array('template' => $this->plan->get_template())); $data = new stdClass(); @@ -81,40 +79,27 @@ class plan_page implements renderable, templatable { $ucexporter = 'core_competency\\external\\user_competency_exporter'; } + $helper = new performance_helper(); $pclist = api::list_plan_competencies($this->plan); $proficientcount = 0; foreach ($pclist as $pc) { $comp = $pc->competency; $usercomp = $pc->$ucproperty; - // Get the framework. - if (!isset($frameworks[$comp->get_competencyframeworkid()])) { - $frameworks[$comp->get_competencyframeworkid()] = $comp->get_framework(); - } - $framework = $frameworks[$comp->get_competencyframeworkid()]; - - // Get the scale. - $scaleid = $comp->get_scaleid(); - $compscale = $comp->get_scale(); - if ($scaleid === null) { - $scaleid = $framework->get_scaleid(); - $compscale = $framework->get_scale(); - } - if (!isset($scales[$scaleid])) { - $scales[$scaleid] = $compscale; - } - $scale = $scales[$scaleid]; + $compcontext = $helper->get_context_from_competency($comp); + $framework = $helper->get_framework_from_competency($comp); + $scale = $helper->get_scale_from_competency($comp); // Prepare the data. $record = new stdClass(); - $exporter = new competency_exporter($comp, array('context' => $framework->get_context())); + $exporter = new competency_exporter($comp, array('context' => $compcontext)); $record->competency = $exporter->export($output); // Competency path. $exporter = new competency_path_exporter([ 'ancestors' => $comp->get_ancestors(), 'framework' => $framework, - 'context' => $framework->get_context() + 'context' => $compcontext ]); $record->comppath = $exporter->export($output); diff --git a/admin/tool/lp/classes/output/template_competencies_page.php b/admin/tool/lp/classes/output/template_competencies_page.php index e51b13d1dbb..eff7ab7b03f 100644 --- a/admin/tool/lp/classes/output/template_competencies_page.php +++ b/admin/tool/lp/classes/output/template_competencies_page.php @@ -34,6 +34,7 @@ use moodle_url; use core_competency\external\template_exporter; use core_competency\template; use core_competency\api; +use core_competency\external\performance_helper; use tool_lp\external\competency_summary_exporter; use tool_lp\external\template_statistics_exporter; use tool_lp\template_statistics; @@ -95,17 +96,10 @@ class template_competencies_page implements renderable, templatable { $data->template = (new template_exporter($this->template))->export($output); $data->pagecontextid = $this->pagecontext->id; $data->competencies = array(); - $contextcache = array(); - $frameworkcache = array(); + $helper = new performance_helper(); foreach ($this->competencies as $competency) { - if (!isset($contextcache[$competency->get_competencyframeworkid()])) { - $contextcache[$competency->get_competencyframeworkid()] = $competency->get_context(); - } - $context = $contextcache[$competency->get_competencyframeworkid()]; - if (!isset($frameworkcache[$competency->get_competencyframeworkid()])) { - $frameworkcache[$competency->get_competencyframeworkid()] = $competency->get_framework(); - } - $framework = $frameworkcache[$competency->get_competencyframeworkid()]; + $context = $helper->get_context_from_competency($competency); + $framework = $helper->get_framework_from_competency($competency); $courses = api::list_courses_using_competency($competency->get_id()); $relatedcompetencies = api::list_related_competencies($competency->get_id()); diff --git a/admin/tool/lp/classes/output/user_competency_course_navigation.php b/admin/tool/lp/classes/output/user_competency_course_navigation.php index 3d716b5a55a..d7b011ed027 100644 --- a/admin/tool/lp/classes/output/user_competency_course_navigation.php +++ b/admin/tool/lp/classes/output/user_competency_course_navigation.php @@ -27,8 +27,9 @@ use renderable; use renderer_base; use templatable; use context_course; -use \core_competency\external\competency_exporter; -use \core_competency\external\user_summary_exporter; +use core_competency\external\competency_exporter; +use core_competency\external\user_summary_exporter; +use core_competency\external\performance_helper; use stdClass; /** @@ -118,14 +119,9 @@ class user_competency_course_navigation implements renderable, templatable { $coursecompetencies = \core_competency\api::list_course_competencies($this->courseid); $data->competencies = array(); - $contextcache = array(); + $helper = new performance_helper(); foreach ($coursecompetencies as $coursecompetency) { - $frameworkid = $coursecompetency['competency']->get_competencyframeworkid(); - if (!isset($contextcache[$frameworkid])) { - $contextcache[$frameworkid] = $coursecompetency['competency']->get_context(); - } - $context = $contextcache[$frameworkid]; - $coursecompetencycontext = $context; + $coursecompetencycontext = $helper->get_context_from_competency($coursecompetency['competency']); $exporter = new competency_exporter($coursecompetency['competency'], array('context' => $coursecompetencycontext)); $competency = $exporter->export($output); if ($competency->id == $this->competencyid) { diff --git a/competency/classes/external.php b/competency/classes/external.php index 9f4bbbb69b4..04162196ade 100644 --- a/competency/classes/external.php +++ b/competency/classes/external.php @@ -49,6 +49,7 @@ use core_competency\external\competency_framework_exporter; use core_competency\external\course_competency_exporter; use core_competency\external\course_competency_settings_exporter; use core_competency\external\evidence_exporter; +use core_competency\external\performance_helper; use core_competency\external\plan_exporter; use core_competency\external\template_exporter; use core_competency\external\user_competency_exporter; @@ -1338,14 +1339,12 @@ class external extends external_api { $result = array(); $contextcache = array(); + $helper = new performance_helper(); foreach ($competencies as $competency) { - if (!isset($contextcache[$competency['competency']->get_competencyframeworkid()])) { - $contextcache[$competency['competency']->get_competencyframeworkid()] = $competency['competency']->get_context(); - } - $context = $contextcache[$competency['competency']->get_competencyframeworkid()]; + $context = $helper->get_context_from_competency($competency['competency']); $exporter = new competency_exporter($competency['competency'], array('context' => $context)); $competencyrecord = $exporter->export($output); - $exporter = new course_competency_exporter($competency['coursecompetency'], array('context' => $context)); + $exporter = new course_competency_exporter($competency['coursecompetency']); $coursecompetencyrecord = $exporter->export($output); $result[] = array( @@ -2149,13 +2148,10 @@ class external extends external_api { $competencies = api::list_competencies_in_template($params['id']); $results = array(); - $contextcache = array(); + $helper = new performance_helper(); foreach ($competencies as $competency) { - if (!isset($contextcache[$competency->get_competencyframeworkid()])) { - $contextcache[$competency->get_competencyframeworkid()] = $competency->get_context(); - } - $context = $contextcache[$competency->get_competencyframeworkid()]; + $context = $helper->get_context_from_competency($competency); $exporter = new competency_exporter($competency, array('context' => $context)); $record = $exporter->export($output); array_push($results, $record); @@ -3145,19 +3141,10 @@ class external extends external_api { $ucproperty = 'usercompetency'; } - $contextcache = array(); - $scalecache = array(); - + $helper = new performance_helper(); foreach ($result as $key => $r) { - if (!isset($scalecache[$r->competency->get_competencyframeworkid()])) { - $scalecache[$r->competency->get_competencyframeworkid()] = $r->competency->get_framework()->get_scale(); - } - $scale = $scalecache[$r->competency->get_competencyframeworkid()]; - - if (!isset($contextcache[$r->competency->get_competencyframeworkid()])) { - $contextcache[$r->competency->get_competencyframeworkid()] = $r->competency->get_context(); - } - $context = $contextcache[$r->competency->get_competencyframeworkid()]; + $context = $helper->get_context_from_competency($r->competency); + $scale = $helper->get_scale_from_competency($r->competency); $exporter = new competency_exporter($r->competency, array('context' => $context)); $r->competency = $exporter->export($output); diff --git a/competency/classes/external/performance_helper.php b/competency/classes/external/performance_helper.php new file mode 100644 index 00000000000..5630a3ffa79 --- /dev/null +++ b/competency/classes/external/performance_helper.php @@ -0,0 +1,111 @@ +. + +/** + * Performance helper. + * + * @package core_competency + * @copyright 2016 Frédéric Massart - FMCorz.net + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core_competency\external; +defined('MOODLE_INTERNAL') || die(); + +use core_competency\competency; + +/** + * Performance helper class. + * + * This tool keeps a local cache of certain items, which means that subsequent + * calls to get the resource will not query the database. You will want to use + * this when many resources could be shared and need to be queried in a loop. + * + * Note that some of these improvements can only be achieved by knowing the + * logic deeper in other modules. For instance we know that a competency's context + * is the one of its framework. This tool must be kept in sync with those APIs. + * + * @package core_competency + * @copyright 2016 Frédéric Massart - FMCorz.net + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class performance_helper { + + /** @var \context Cache of contexts by framework ID. */ + protected $frameworkscontexts = []; + + /** @var competency_framework Cache of frameworks by framework ID. */ + protected $frameworks = []; + + /** @var \grade_scale[] Cache of scales by scale ID. */ + protected $scales = []; + + /** + * Get the context of a competency. + * + * @param competency $competency The competency. + * @return \context + */ + public function get_context_from_competency(competency $competency) { + $frameworkid = $competency->get_competencyframeworkid(); + if (!isset($this->frameworkscontexts[$frameworkid])) { + $framework = $this->get_framework_from_competency($competency); + $this->frameworkscontexts[$frameworkid] = $framework->get_context(); + } + return $this->frameworkscontexts[$frameworkid]; + } + + /** + * Get the framework of a competency. + * + * @param competency $competency The competency. + * @return competency_framework + */ + public function get_framework_from_competency(competency $competency) { + $frameworkid = $competency->get_competencyframeworkid(); + if (!isset($this->frameworks[$frameworkid])) { + $this->frameworks[$frameworkid] = $competency->get_framework(); + } + return $this->frameworks[$frameworkid]; + } + + /** + * Get the scale of a competency. + * + * /!\ Make sure that this is always kept in sync with: + * - core_competency\competency::get_scale() + * - core_competency\competency_framework::get_scale() + * + * @param competency $competency The competency. + * @return \grade_scale + */ + public function get_scale_from_competency(competency $competency) { + $scaleid = $competency->get_scaleid(); + if ($scaleid !== null && !isset($this->scales[$scaleid])) { + $this->scales[$scaleid] = $competency->get_scale(); + + } else if ($scaleid === null) { + $framework = $this->get_framework_from_competency($competency); + $scaleid = $framework->get_scaleid(); + if (!isset($this->scales[$scaleid])) { + $this->scales[$scaleid] = $framework->get_scale(); + } + } + + return $this->scales[$scaleid]; + } + +} diff --git a/competency/classes/external/user_evidence_exporter.php b/competency/classes/external/user_evidence_exporter.php index d7774767b4a..291c62988b8 100644 --- a/competency/classes/external/user_evidence_exporter.php +++ b/competency/classes/external/user_evidence_exporter.php @@ -76,15 +76,11 @@ class user_evidence_exporter extends \core\external\persistent_exporter { } protected function get_other_values(renderer_base $output) { - $contextcache = array(); + $helper = new performance_helper(); $competencies = array(); foreach ($this->related['competencies'] as $competency) { - if (!isset($contextcache[$competency->get_competencyframeworkid()])) { - $contextcache[$competency->get_competencyframeworkid()] = $competency->get_context(); - } - $context = $contextcache[$competency->get_competencyframeworkid()]; - + $context = $helper->get_context_from_competency($competency); $compexporter = new competency_exporter($competency, array('context' => $context)); $competencies[] = $compexporter->export($output); } diff --git a/competency/tests/generator/lib.php b/competency/tests/generator/lib.php index 40068251201..108ce41260f 100644 --- a/competency/tests/generator/lib.php +++ b/competency/tests/generator/lib.php @@ -114,6 +114,9 @@ class core_competency_generator extends component_generator_base { if (!isset($record->descriptionformat)) { $record->descriptionformat = FORMAT_HTML; } + if (!isset($record->scaleconfiguration) && isset($record->scaleid)) { + $record->scaleconfiguration = json_encode($this->make_default_scale_configuration($record->scaleid)); + } if (isset($record->scaleconfiguration) && (is_array($record->scaleconfiguration) || is_object($record->scaleconfiguration))) { // Conveniently encode the config. @@ -163,31 +166,7 @@ class core_competency_generator extends component_generator_base { $record->scaleid = $this->scale->id; } if (!isset($record->scaleconfiguration)) { - $scale = grade_scale::fetch(array('id' => $record->scaleid)); - $values = $scale->load_items(); - foreach ($values as $key => $value) { - // Add a key (make the first value 1). - $values[$key] = array('id' => $key + 1, 'name' => $value); - } - if (count($values) < 2) { - throw new coding_exception('Please provide the scale configuration for one-item scales.'); - } - $scaleconfig = array(); - // Last item is proficient. - $item = array_pop($values); - array_unshift($scaleconfig, array( - 'id' => $item['id'], - 'proficient' => 1 - )); - // Second-last item is default and proficient. - $item = array_pop($values); - array_unshift($scaleconfig, array( - 'id' => $item['id'], - 'scaledefault' => 1, - 'proficient' => 1 - )); - array_unshift($scaleconfig, array('scaleid' => $record->scaleid)); - $record->scaleconfiguration = json_encode($scaleconfig); + $record->scaleconfiguration = json_encode($this->make_default_scale_configuration($record->scaleid)); } if (is_array($record->scaleconfiguration) || is_object($record->scaleconfiguration)) { // Conveniently encode the config. @@ -559,5 +538,50 @@ class core_competency_generator extends component_generator_base { return $uec; } + /** + * Make a default scale configuration. + * + * The last and second-last item will be flagged proficient. The + * second-last item will be flagged as default. + * + * @param int $scaleid The scale ID. + * @return array Configuration as array. + */ + protected function make_default_scale_configuration($scaleid) { + $scale = grade_scale::fetch(array('id' => $scaleid)); + $values = $scale->load_items(); + + foreach ($values as $key => $value) { + // Add a key (make the first value 1). + $values[$key] = array('id' => $key + 1, 'name' => $value); + } + + if (count($values) < 2) { + throw new coding_exception('Please provide the scale configuration for one-item scales.'); + } + + $scaleconfig = array(); + + // Last item is proficient. + $item = array_pop($values); + array_unshift($scaleconfig, array( + 'id' => $item['id'], + 'proficient' => 1 + )); + + // Second-last item is default and proficient. + $item = array_pop($values); + array_unshift($scaleconfig, array( + 'id' => $item['id'], + 'scaledefault' => 1, + 'proficient' => 1 + )); + + // Add the scale ID. + array_unshift($scaleconfig, array('scaleid' => $scaleid)); + + return $scaleconfig; + } + } diff --git a/competency/tests/performance_helper_test.php b/competency/tests/performance_helper_test.php new file mode 100644 index 00000000000..3c95a3124ff --- /dev/null +++ b/competency/tests/performance_helper_test.php @@ -0,0 +1,159 @@ +. + +/** + * Performance helper tests. + * + * @package core_competency + * @copyright 2016 Frédéric Massart - FMCorz.net + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); +global $CFG; + +use core_competency\external\performance_helper; + +/** + * Performance helper testcase. + * + * @package core_competency + * @copyright 2016 Frédéric Massart - FMCorz.net + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class core_competency_performance_helper_testcase extends advanced_testcase { + + public function test_get_context_from_competency() { + global $DB; + + $this->resetAfterTest(true); + $dg = $this->getDataGenerator(); + $lpg = $dg->get_plugin_generator('core_competency'); + + $cat1 = $dg->create_category(); + $framework = $lpg->create_framework(); + $competency = $lpg->create_competency(['competencyframeworkid' => $framework->get_id()]); + $competency2 = $lpg->create_competency(['competencyframeworkid' => $framework->get_id()]); + + $context = $competency->get_context(); + $helper = new performance_helper(); + $initdbqueries = $DB->perf_get_queries(); + + // Confirm that subsequent calls return a cached object. + // Note that here we check that the framework is not loaded more than once. + // The context objects are already cached in the context layer. + $firstruncontext = $helper->get_context_from_competency($competency); + $dbqueries = $DB->perf_get_queries(); + $this->assertSame($context, $firstruncontext); + $this->assertNotEquals($initdbqueries, $dbqueries); + + $secondruncontext = $helper->get_context_from_competency($competency); + $this->assertSame($context, $secondruncontext); + $this->assertSame($firstruncontext, $secondruncontext); + $this->assertEquals($DB->perf_get_queries(), $dbqueries); + + $thirdruncontext = $helper->get_context_from_competency($competency2); + $this->assertSame($context, $thirdruncontext); + $this->assertSame($secondruncontext, $thirdruncontext); + $this->assertEquals($DB->perf_get_queries(), $dbqueries); + } + + public function test_get_framework_from_competency() { + global $DB; + + $this->resetAfterTest(true); + $dg = $this->getDataGenerator(); + $lpg = $dg->get_plugin_generator('core_competency'); + + $cat1 = $dg->create_category(); + $framework1 = $lpg->create_framework(); + $comp1a = $lpg->create_competency(['competencyframeworkid' => $framework1->get_id()]); + $comp1b = $lpg->create_competency(['competencyframeworkid' => $framework1->get_id()]); + $framework2 = $lpg->create_framework(); + $comp2a = $lpg->create_competency(['competencyframeworkid' => $framework2->get_id()]); + + $helper = new performance_helper(); + $initdbqueries = $DB->perf_get_queries(); + + // Confirm that we get the right framework, and that subsequent calls + // do not trigger DB queries, even for other competencies. + $firstrunframework = $helper->get_framework_from_competency($comp1a); + $firstrundbqueries = $DB->perf_get_queries(); + $this->assertNotEquals($initdbqueries, $firstrundbqueries); + $this->assertEquals($framework1, $firstrunframework); + $this->assertNotSame($framework1, $firstrunframework); + + $secondrunframework = $helper->get_framework_from_competency($comp1b); + $this->assertEquals($firstrundbqueries, $DB->perf_get_queries()); + $this->assertEquals($framework1, $secondrunframework); + $this->assertSame($firstrunframework, $secondrunframework); + + $thirdrunframework = $helper->get_framework_from_competency($comp1a); + $this->assertEquals($firstrundbqueries, $DB->perf_get_queries()); + $this->assertEquals($framework1, $thirdrunframework); + $this->assertSame($firstrunframework, $thirdrunframework); + + // Fetch another framework. + $fourthrunframework = $helper->get_framework_from_competency($comp2a); + $fourthrundbqueries = $DB->perf_get_queries(); + $this->assertNotEquals($firstrundbqueries, $fourthrundbqueries); + $this->assertEquals($framework2, $fourthrunframework); + $this->assertNotSame($framework2, $fourthrunframework); + + $fifthrunframework = $helper->get_framework_from_competency($comp2a); + $this->assertEquals($fourthrundbqueries, $DB->perf_get_queries()); + $this->assertEquals($framework2, $fifthrunframework); + $this->assertSame($fourthrunframework, $fifthrunframework); + } + + public function test_get_scale_from_competency() { + global $DB; + + $this->resetAfterTest(true); + $dg = $this->getDataGenerator(); + $lpg = $dg->get_plugin_generator('core_competency'); + + $scale1 = $dg->create_scale(); + $scale2 = $dg->create_scale(); + $cat1 = $dg->create_category(); + + $framework1 = $lpg->create_framework(['scaleid' => $scale1->id]); + $comp1 = $lpg->create_competency(['competencyframeworkid' => $framework1->get_id()]); + $comp2 = $lpg->create_competency(['competencyframeworkid' => $framework1->get_id(), 'scaleid' => $scale2->id]); + $comp3 = $lpg->create_competency(['competencyframeworkid' => $framework1->get_id()]); + + $helper = new performance_helper(); + $initdbqueries = $DB->perf_get_queries(); + + // Get the first scale. + $firstrunscale = $helper->get_scale_from_competency($comp1); + $firstrundbqueries = $DB->perf_get_queries(); + $this->assertNotEquals($initdbqueries, $firstrundbqueries); + $this->assertEquals($scale1, $firstrunscale->get_record_data()); + + $secondrunscale = $helper->get_scale_from_competency($comp3); + $this->assertEquals($firstrundbqueries, $DB->perf_get_queries()); + $this->assertSame($firstrunscale, $secondrunscale); + + // Another scale, and its subsequent calls. + $thirdrunscale = $helper->get_scale_from_competency($comp2); + $thirddbqueries = $DB->perf_get_queries(); + $this->assertNotEquals($firstrundbqueries, $thirddbqueries); + $this->assertEquals($scale2, $thirdrunscale->get_record_data()); + $this->assertSame($thirdrunscale, $helper->get_scale_from_competency($comp2)); + $this->assertEquals($thirddbqueries, $DB->perf_get_queries()); + } +} diff --git a/report/competency/classes/output/report.php b/report/competency/classes/output/report.php index c3e296e5635..47ca93b74fa 100644 --- a/report/competency/classes/output/report.php +++ b/report/competency/classes/output/report.php @@ -33,6 +33,7 @@ use stdClass; use core_competency\api; use core_competency\external\user_competency_course_exporter; use core_competency\external\user_summary_exporter; +use core_competency\external\performance_helper; use core_competency\url; use core_competency\user_competency; use tool_lp\external\competency_summary_exporter; @@ -85,9 +86,6 @@ class report implements renderable, templatable { $data->course = $exporter->export($output); $data->usercompetencies = array(); - $scalecache = array(); - $frameworkcache = array(); - $user = core_user::get_user($this->userid); $exporter = new user_summary_exporter($user); @@ -96,6 +94,7 @@ class report implements renderable, templatable { $coursecompetencies = api::list_course_competencies($this->courseid); $usercompetencycourses = api::list_user_competencies_in_course($this->courseid, $user->id); + $helper = new performance_helper(); foreach ($usercompetencycourses as $usercompetencycourse) { $onerow = new stdClass(); $competency = null; @@ -108,24 +107,9 @@ class report implements renderable, templatable { if (!$competency) { continue; } - // Fetch the framework. - if (!isset($frameworkcache[$competency->get_competencyframeworkid()])) { - $frameworkcache[$competency->get_competencyframeworkid()] = $competency->get_framework(); - } - $framework = $frameworkcache[$competency->get_competencyframeworkid()]; - // Fetch the scale. - $scaleid = $competency->get_scaleid(); - if ($scaleid === null) { - $scaleid = $framework->get_scaleid(); - if (!isset($scalecache[$scaleid])) { - $scalecache[$competency->get_scaleid()] = $framework->get_scale(); - } - - } else if (!isset($scalecache[$scaleid])) { - $scalecache[$competency->get_scaleid()] = $competency->get_scale(); - } - $scale = $scalecache[$competency->get_scaleid()]; + $framework = $helper->get_framework_from_competency($competency); + $scale = $helper->get_scale_from_competency($competency); $exporter = new user_competency_course_exporter($usercompetencycourse, array('scale' => $scale)); $record = $exporter->export($output);