/** * Export this data so it can be used as the context for a mustache template. * * @param renderer_base $output Renderer base. * @return stdClass */ public function export_for_template(renderer_base $output) { global $USER; $data = new stdClass(); $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) { $usercompetencycourses = api::list_user_competencies_in_course($this->courseid, $USER->id); $data->gradableuserid = $USER->id; } $ruleoutcomelist = course_competency::get_ruleoutcome_list(); $ruleoutcomeoptions = array(); foreach ($ruleoutcomelist as $value => $text) { $ruleoutcomeoptions[$value] = array('value' => $value, 'text' => (string) $text, 'selected' => false); } 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()]; $compexporter = new competency_exporter($competency, array('context' => $context)); $ccexporter = new course_competency_exporter($coursecompetency, array('context' => $context)); $ccoutcomeoptions = (array) (object) $ruleoutcomeoptions; $ccoutcomeoptions[$coursecompetency->get_ruleoutcome()]['selected'] = true; $coursemodules = api::list_course_modules_using_competency($competency->get_id(), $this->courseid); $fastmodinfo = get_fast_modinfo($this->courseid); $exportedmodules = array(); foreach ($coursemodules as $cmid) { $cminfo = $fastmodinfo->cms[$cmid]; $cmexporter = new course_module_summary_exporter(null, array('cm' => $cminfo)); $exportedmodules[] = $cmexporter->export($output); } // Competency path. $pathexporter = new competency_path_exporter(['ancestors' => $competency->get_ancestors(), 'framework' => $competency->get_framework(), 'context' => $context]); $onerow = array('competency' => $compexporter->export($output), 'coursecompetency' => $ccexporter->export($output), 'ruleoutcomeoptions' => $ccoutcomeoptions, 'coursemodules' => $exportedmodules, 'comppath' => $pathexporter->export($output)); if ($gradable) { $foundusercompetencycourse = false; foreach ($usercompetencycourses as $usercompetencycourse) { if ($usercompetencycourse->get_competencyid() == $competency->get_id()) { $foundusercompetencycourse = $usercompetencycourse; } } if ($foundusercompetencycourse) { $related = array('scale' => $competency->get_scale()); $exporter = new user_competency_course_exporter($foundusercompetencycourse, $related); $onerow['usercompetencycourse'] = $exporter->export($output); } } array_push($data->competencies, $onerow); } $data->canmanagecompetencyframeworks = $this->canmanagecompetencyframeworks; $data->canmanagecoursecompetencies = $this->canmanagecoursecompetencies; $data->canconfigurecoursecompetencies = $this->canconfigurecoursecompetencies; $data->cangradecompetencies = $this->cangradecompetencies; $exporter = new course_competency_settings_exporter($this->coursecompetencysettings); $data->settings = $exporter->export($output); $related = array('context' => $this->context); $exporter = new course_competency_statistics_exporter($this->coursecompetencystatistics, $related); $data->statistics = $exporter->export($output); $data->manageurl = null; if ($this->canmanagecompetencyframeworks) { $data->manageurl = $this->manageurl->out(true); } return $data; }
/** * Test update ruleoutcome for course_competency. */ public function test_set_ruleoutcome_course_competency() { $this->resetAfterTest(true); $dg = $this->getDataGenerator(); $lpg = $dg->get_plugin_generator('core_competency'); $u1 = $dg->create_user(); $u2 = $dg->create_user(); $course = $dg->create_course(); $this->setAdminUser(); $f = $lpg->create_framework(); $c = $lpg->create_competency(array('competencyframeworkid' => $f->get_id())); $cc = api::add_competency_to_course($course->id, $c->get_id()); // Check record was created with default rule value Evidence. $this->assertEquals(1, \core_competency\course_competency::count_records()); $recordscc = api::list_course_competencies($course->id); $this->assertEquals(\core_competency\course_competency::OUTCOME_EVIDENCE, $recordscc[0]['coursecompetency']->get_ruleoutcome()); // Check ruleoutcome value is updated to None. $this->assertTrue(api::set_course_competency_ruleoutcome($recordscc[0]['coursecompetency']->get_id(), \core_competency\course_competency::OUTCOME_NONE)); $recordscc = api::list_course_competencies($course->id); $this->assertEquals(\core_competency\course_competency::OUTCOME_NONE, $recordscc[0]['coursecompetency']->get_ruleoutcome()); }
public function test_hook_course_reset_competency_ratings() { $this->resetAfterTest(); $dg = $this->getDataGenerator(); $ccg = $dg->get_plugin_generator('core_competency'); $u1 = $dg->create_user(); $framework = $ccg->create_framework(); $comp1 = $ccg->create_competency(['competencyframeworkid' => $framework->get_id()]); $comp2 = $ccg->create_competency(['competencyframeworkid' => $framework->get_id()]); $c1 = $dg->create_course(); $cc1a = $ccg->create_course_competency(['competencyid' => $comp1->get_id(), 'courseid' => $c1->id]); $cc1b = $ccg->create_course_competency(['competencyid' => $comp2->get_id(), 'courseid' => $c1->id]); $assign1a = $dg->create_module('assign', ['course' => $c1]); $assign1b = $dg->create_module('assign', ['course' => $c1]); $cmc1a = $ccg->create_course_module_competency(['competencyid' => $comp1->get_id(), 'cmid' => $assign1a->cmid]); $cmc1b = $ccg->create_course_module_competency(['competencyid' => $comp1->get_id(), 'cmid' => $assign1b->cmid]); $ucc1a = $ccg->create_user_competency_course(['competencyid' => $comp1->get_id(), 'courseid' => $c1->id, 'userid' => $u1->id]); $ucc1b = $ccg->create_user_competency_course(['competencyid' => $comp2->get_id(), 'courseid' => $c1->id, 'userid' => $u1->id]); $c2 = $dg->create_course(); $cc2a = $ccg->create_course_competency(['competencyid' => $comp1->get_id(), 'courseid' => $c2->id]); $cc2b = $ccg->create_course_competency(['competencyid' => $comp2->get_id(), 'courseid' => $c2->id]); $assign2a = $dg->create_module('assign', ['course' => $c2]); $assign2b = $dg->create_module('assign', ['course' => $c2]); $cmc2a = $ccg->create_course_module_competency(['competencyid' => $comp1->get_id(), 'cmid' => $assign2a->cmid]); $cmc2b = $ccg->create_course_module_competency(['competencyid' => $comp1->get_id(), 'cmid' => $assign2b->cmid]); $ucc2a = $ccg->create_user_competency_course(['competencyid' => $comp1->get_id(), 'courseid' => $c2->id, 'userid' => $u1->id]); $ucc2b = $ccg->create_user_competency_course(['competencyid' => $comp2->get_id(), 'courseid' => $c2->id, 'userid' => $u1->id]); reset_course_userdata((object) ['id' => $c1->id, 'reset_competency_ratings' => true]); $this->assertEquals(2, course_competency::count_records(['courseid' => $c1->id])); $this->assertEquals(2, course_competency::count_records(['courseid' => $c2->id])); $this->assertEquals(1, course_module_competency::count_records(['cmid' => $assign1a->cmid])); $this->assertEquals(1, course_module_competency::count_records(['cmid' => $assign1b->cmid])); $this->assertEquals(1, course_module_competency::count_records(['cmid' => $assign2a->cmid])); $this->assertEquals(1, course_module_competency::count_records(['cmid' => $assign2b->cmid])); $this->assertEquals(0, user_competency_course::count_records(['courseid' => $c1->id, 'userid' => $u1->id])); $this->assertEquals(2, user_competency_course::count_records(['courseid' => $c2->id, 'userid' => $u1->id])); }
/** * Manually grade a user course competency from the course page. * * This may push the rating to the user competency * if the course is configured this way. * * @param mixed $courseorid * @param int $userid * @param int $competencyid * @param int $grade * @param string $note A note to attach to the evidence * @return array of \core_competency\user_competency */ public static function grade_competency_in_course($courseorid, $userid, $competencyid, $grade, $note = null) { global $USER, $DB; static::require_enabled(); $course = $courseorid; if (!is_object($courseorid)) { $course = $DB->get_record('course', array('id' => $courseorid)); } $context = context_course::instance($course->id); // Check that we can view the user competency details in the course. if (!user_competency::can_read_user_in_course($userid, $course->id)) { throw new required_capability_exception($context, 'moodle/competency:usercompetencyview', 'nopermissions', ''); } // Validate the permission to grade. if (!user_competency::can_grade_user_in_course($userid, $course->id)) { throw new required_capability_exception($context, 'moodle/competency:competencygrade', 'nopermissions', ''); } // Check that competency is in course and visible to the current user. $competency = course_competency::get_competency($course->id, $competencyid); $competencycontext = $competency->get_context(); if (!has_any_capability(array('moodle/competency:competencyview', 'moodle/competency:competencymanage'), $competencycontext)) { throw new required_capability_exception($competencycontext, 'moodle/competency:competencyview', 'nopermissions', ''); } // Check that the user is enrolled in the course, and is "gradable". if (!is_enrolled($context, $userid, 'moodle/competency:coursecompetencygradable')) { throw new coding_exception('The competency may not be rated at this time.'); } $action = evidence::ACTION_OVERRIDE; $desckey = 'evidence_manualoverrideincourse'; $result = self::add_evidence($userid, $competency, $context->id, $action, $desckey, 'core_competency', $context->get_context_name(), false, null, $grade, $USER->id, $note); if ($result) { $all = user_competency_course::get_multiple($userid, $course->id, array($competency->get_id())); $uc = reset($all); $event = \core\event\competency_user_competency_rated_in_course::create_from_user_competency_course($uc); $event->trigger(); } return $result; }
/** * Process a course competency. * * @param array $data The data. */ public function process_course_competency($data) { $data = (object) $data; // Mapping the competency by ID numbers. $framework = \core_competency\competency_framework::get_record(array('idnumber' => $data->frameworkidnumber)); if (!$framework) { return; } $competency = \core_competency\competency::get_record(array('idnumber' => $data->idnumber, 'competencyframeworkid' => $framework->get_id())); if (!$competency) { return; } $this->set_mapping(\core_competency\competency::TABLE, $data->id, $competency->get_id()); $params = array('competencyid' => $competency->get_id(), 'courseid' => $this->task->get_courseid()); $query = 'competencyid = :competencyid AND courseid = :courseid'; $existing = \core_competency\course_competency::record_exists_select($query, $params); if (!$existing) { // Sortorder is ignored by precaution, anyway we should walk through the records in the right order. $record = (object) $params; $record->ruleoutcome = $data->ruleoutcome; $coursecompetency = new \core_competency\course_competency(0, $record); $coursecompetency->create(); } }
/** * Create a new course competency. * * @param array|stdClass $record * @return user_competency */ public function create_course_competency($record = null) { $record = (object) $record; if (!isset($record->courseid)) { throw new coding_exception('The courseid value is required.'); } if (!isset($record->competencyid)) { throw new coding_exception('The competencyid value is required.'); } $cc = new course_competency(0, $record); $cc->create(); return $cc; }
/** * Process each course individually. * @return void */ protected function process_courses() { global $DB; $this->progress->start_progress(get_string('migratingcourses', 'tool_lpmigrate'), count($this->coursescompetencies)); // Process each course. foreach ($this->coursescompetencies as $courseid => $competencyids) { $this->progress->increment_progress(); $competenciestoremovefromcourse = array(); $skipcompetencies = array(); // First, add all the new competencies to the course. foreach ($competencyids as $key => $competencyid) { $this->coursecompetencyexpectedmigrations++; $mapto = isset($this->mappings[$competencyid]) ? $this->mappings[$competencyid] : false; // Skip the competencies that are not mapped. if ($mapto === false) { $this->missingmappings[$competencyid] = true; if ($this->removewhenmappingismissing) { $competenciestoremovefromcourse[$competencyid] = true; } continue; } $transaction = $DB->start_delegated_transaction(); try { // Add the new competency to the course. if (api::add_competency_to_course($courseid, $mapto)) { // Find the added course competency. $cc = course_competency::get_record(array('courseid' => $courseid, 'competencyid' => $mapto)); // Set the rule. api::set_course_competency_ruleoutcome($cc, $this->coursescompetenciesoutcomes[$courseid][$competencyid]); // Adapt the sortorder. api::reorder_course_competency($courseid, $mapto, $competencyid); $competenciestoremovefromcourse[$competencyid] = true; $this->coursecompetencymigrations++; } else { // The competency was already in the course... if ($this->removeoriginalwhenalreadypresent) { $competenciestoremovefromcourse[$competencyid] = true; } else { $this->log_warning($courseid, $competencyid, null, get_string('warningdestinationcoursecompetencyalreadyexists', 'tool_lpmigrate')); } } } catch (moodle_exception $e) { // There was a major problem with this competency, we will ignore it entirely for the course. $skipcompetencies[$competencyid] = true; $this->log_error($courseid, $competencyid, null, get_string('errorwhilemigratingcoursecompetencywithexception', 'tool_lpmigrate', $e->getMessage())); try { $transaction->rollback($e); } catch (moodle_exception $e) { // Catch the re-thrown exception. } continue; } $transaction->allow_commit(); } // Then, convert the module competencies. if (!empty($this->modulecompetencies[$courseid])) { foreach ($this->modulecompetencies[$courseid] as $cmid => $competencyids) { foreach ($competencyids as $competencyid) { $this->modulecompetencyexpectedmigrations++; // This mapped competency was not added to the course. if (!empty($skipcompetencies[$competencyid])) { continue; } $remove = true; $mapto = isset($this->mappings[$competencyid]) ? $this->mappings[$competencyid] : false; // We don't have mapping. if ($mapto === false) { if (!$this->removewhenmappingismissing) { $remove = false; } } else { // We have a mapping. $transaction = $DB->start_delegated_transaction(); try { // The competency was added successfully. if (api::add_competency_to_course_module($cmid, $mapto)) { // Find the added module competency. $mc = course_module_competency::get_record(array('cmid' => $cmid, 'competencyid' => $mapto)); // Set the competency rule. api::set_course_module_competency_ruleoutcome($mc, $this->modulecompetenciesoutcomes[$courseid][$cmid][$competencyid]); // Adapt the sortorder. api::reorder_course_module_competency($cmid, $mapto, $competencyid); $this->modulecompetencymigrations++; } else { // The competency was already in the module. if (!$this->removeoriginalwhenalreadypresent) { $remove = false; $competencieswithissues[$competencyid] = true; $this->log_warning($courseid, $competencyid, $cmid, get_string('warningdestinationmodulecompetencyalreadyexists', 'tool_lpmigrate')); } } } catch (moodle_exception $e) { // There was a major problem with this competency in this module. $competencieswithissues[$competencyid] = true; $message = get_string('errorwhilemigratingmodulecompetencywithexception', 'tool_lpmigrate', $e->getMessage()); $this->log_error($courseid, $competencyid, $cmid, $message); try { $transaction->rollback($e); } catch (moodle_exception $e) { // Catch the re-thrown exception. } continue; } $transaction->allow_commit(); } try { // Go away competency! if ($remove && api::remove_competency_from_course_module($cmid, $competencyid)) { $this->modulecompetencyremovals++; } } catch (moodle_exception $e) { $competencieswithissues[$competencyid] = true; $this->log_warning($courseid, $competencyid, $cmid, get_string('warningcouldnotremovemodulecompetency', 'tool_lpmigrate')); } } } } // Finally, we remove the course competencies, but only for the 100% successful ones. foreach ($competenciestoremovefromcourse as $competencyid => $unused) { // Skip competencies with issues. if (isset($competencieswithissues[$competencyid])) { continue; } try { // Process the course competency. api::remove_competency_from_course($courseid, $competencyid); $this->coursecompetencyremovals++; } catch (moodle_exception $e) { $this->log_warning($courseid, $competencyid, null, get_string('warningcouldnotremovecoursecompetency', 'tool_lpmigrate')); } } } $this->progress->end_progress(); }
/** * Change the ruleoutcome of a course competency. * * @param int $coursecompetencyid The course competency id * @param int $ruleoutcome The ruleoutcome value * @return bool */ public static function set_course_competency_ruleoutcome($coursecompetencyid, $ruleoutcome) { $params = self::validate_parameters(self::set_course_competency_ruleoutcome_parameters(), array('coursecompetencyid' => $coursecompetencyid, 'ruleoutcome' => $ruleoutcome)); $coursecompetency = new course_competency($params['coursecompetencyid']); self::validate_context(context_course::instance($coursecompetency->get_courseid())); return api::set_course_competency_ruleoutcome($coursecompetency, $params['ruleoutcome']); }
/** * Check if we can delete competencies safely. * * This moethod does not check any capablities. * Check if competency is used in a plan and user competency. * Check if competency is used in a template. * Check if competency is linked to a course. * * @param array $ids Array of competencies ids. * @return bool True if we can delete the competencies. */ public static function can_all_be_deleted($ids) { if (empty($ids)) { return true; } // Check if competency is used in template. if (template_competency::has_records_for_competencies($ids)) { return false; } // Check if competency is used in plan. if (plan_competency::has_records_for_competencies($ids)) { return false; } // Check if competency is used in course. if (course_competency::has_records_for_competencies($ids)) { return false; } // Check if competency is used in user_competency. if (user_competency::has_records_for_competencies($ids)) { return false; } // Check if competency is used in user_competency_plan. if (user_competency_plan::has_records_for_competencies($ids)) { return false; } return true; }
/** * Assert that the course competency was migrated. * * @param stdClass $course The course. * @param competency $compfrom The competency from. * @param competency $compto The competency to. */ protected function assertCourseCompetencyMigrated($course, $compfrom, $compto) { $ccs = $this->ccs[$course->id]; $this->assertCourseCompetencyNotExists($course, $compfrom); $this->assertCourseCompetencyExists($course, $compto); $before = $ccs[$compfrom->get_id()]; $after = course_competency::get_record(array('courseid' => $course->id, 'competencyid' => $compto->get_id())); $this->assertNotEquals($before->get_id(), $after->get_id()); $this->assertEquals($before->get_courseid(), $after->get_courseid()); $this->assertEquals($before->get_sortorder(), $after->get_sortorder()); $this->assertEquals($before->get_ruleoutcome(), $after->get_ruleoutcome()); }
public function test_create_course_competency() { $this->resetAfterTest(true); $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency'); $course1 = $this->getDataGenerator()->create_course(); $course2 = $this->getDataGenerator()->create_course(); $framework = $lpg->create_framework(); $c1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id())); $c2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id())); $c3 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id())); $this->assertEquals(0, course_competency::count_records()); $rc = $lpg->create_course_competency(array('competencyid' => $c1->get_id(), 'courseid' => $course1->id)); $rc = $lpg->create_course_competency(array('competencyid' => $c2->get_id(), 'courseid' => $course1->id)); $this->assertEquals(2, course_competency::count_records(array('courseid' => $course1->id))); $this->assertEquals(0, course_competency::count_records(array('courseid' => $course2->id))); $rc = $lpg->create_course_competency(array('competencyid' => $c3->get_id(), 'courseid' => $course2->id)); $this->assertEquals(1, course_competency::count_records(array('courseid' => $course2->id))); $this->assertInstanceOf('\\core_competency\\course_competency', $rc); }
public function test_get_courses_with_competency_and_user() { global $CFG, $DB; $this->resetAfterTest(true); $dg = $this->getDataGenerator(); $lpg = $dg->get_plugin_generator('core_competency'); $c1 = $dg->create_course(); $c2 = $dg->create_course(); $c3 = $dg->create_course(); $c4 = $dg->create_course(); $u1 = $dg->create_user(); $u2 = $dg->create_user(); $u3 = $dg->create_user(); $u4 = $dg->create_user(); $flatfileplugin = enrol_get_plugin('flatfile'); $flatfileinstanceid = $flatfileplugin->add_instance($c2); $framework = $lpg->create_framework(); $comp1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id())); // In C1, and C2. $comp2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id())); // In C2. $comp3 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id())); // In None. $comp4 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id())); // In C4. $lpg->create_course_competency(array('competencyid' => $comp1->get_id(), 'courseid' => $c1->id)); $lpg->create_course_competency(array('competencyid' => $comp1->get_id(), 'courseid' => $c2->id)); $lpg->create_course_competency(array('competencyid' => $comp2->get_id(), 'courseid' => $c2->id)); $lpg->create_course_competency(array('competencyid' => $comp4->get_id(), 'courseid' => $c4->id)); // Enrol the user 1 in C1, C2, and C3. $dg->enrol_user($u1->id, $c1->id); $dg->enrol_user($u1->id, $c2->id); $dg->enrol_user($u1->id, $c3->id); // Enrol the user 2 in C4. $dg->enrol_user($u2->id, $c4->id); // Enrol the user 3 in C1 and C2, but non active in C2. $dg->enrol_user($u3->id, $c1->id); $dg->enrol_user($u3->id, $c2->id, null, 'manual', 0, 0, ENROL_USER_SUSPENDED); // Enrol the user 4 with a plugin which will be enabled/disabled. $dg->enrol_user($u4->id, $c2->id, null, 'flatfile'); // Using the competency that is not used anywhere -> no courses. $this->assertCount(0, course_competency::get_courses_with_competency_and_user($comp3->get_id(), $u1->id)); // Using the competency that is used in a course where the user is not enrolled -> no courses. $this->assertCount(0, course_competency::get_courses_with_competency_and_user($comp4->get_id(), $u1->id)); // Using the competency that is used in a course where the user is enrolled -> one course. $courses = course_competency::get_courses_with_competency_and_user($comp2->get_id(), $u1->id); $this->assertCount(1, $courses); $this->assertArrayHasKey($c2->id, $courses); // Using the competency used multiple times. $courses = course_competency::get_courses_with_competency_and_user($comp1->get_id(), $u1->id); $this->assertCount(2, $courses); $this->assertArrayHasKey($c1->id, $courses); $this->assertArrayHasKey($c2->id, $courses); // Checking for another user where the competency is used twice, but not for them. $courses = course_competency::get_courses_with_competency_and_user($comp1->get_id(), $u2->id); $this->assertCount(0, $courses); // Checking for another user where the competency is used in their course. $courses = course_competency::get_courses_with_competency_and_user($comp4->get_id(), $u2->id); $this->assertCount(1, $courses); $this->assertArrayHasKey($c4->id, $courses); // Checking for a user who is suspended in a course. $courses = course_competency::get_courses_with_competency_and_user($comp1->get_id(), $u3->id); $this->assertCount(1, $courses); $this->assertArrayHasKey($c1->id, $courses); // Check for the user with plugin enabled. $enrolplugins = explode(',', $CFG->enrol_plugins_enabled); $enrolplugins[] = 'flatfile'; $CFG->enrol_plugins_enabled = implode(',', array_unique($enrolplugins)); $courses = course_competency::get_courses_with_competency_and_user($comp1->get_id(), $u4->id); $this->assertCount(1, $courses); $this->assertArrayHasKey($c2->id, $courses); // Check for the user with plugin enabled, but enrolment instance disabled. $flatfileinstance = $DB->get_record('enrol', array('id' => $flatfileinstanceid)); $flatfileplugin->update_status($flatfileinstance, ENROL_INSTANCE_DISABLED); $courses = course_competency::get_courses_with_competency_and_user($comp1->get_id(), $u4->id); $this->assertCount(0, $courses); $flatfileplugin->update_status($flatfileinstance, ENROL_INSTANCE_ENABLED); // Check for the user with plugin disabled. $enrolplugins = array_flip(explode(',', $CFG->enrol_plugins_enabled)); unset($enrolplugins['flatfile']); $CFG->enrol_plugins_enabled = implode(',', array_keys($enrolplugins)); $courses = course_competency::get_courses_with_competency_and_user($comp1->get_id(), $u4->id); $this->assertCount(0, $courses); }