2 // This file is part of Moodle - http://moodle.org/
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
18 * This file contains the badge earned badge award criteria type class
22 * @copyright 2019 Damyon Wiese
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26 defined('MOODLE_INTERNAL') ||
die();
29 * Badge award criteria -- award on competency completion
33 * @copyright 2019 Damyon Wiese
34 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
36 class award_criteria_competency
extends award_criteria
{
38 /* @var int The criteria type */
39 public $criteriatype = BADGE_CRITERIA_TYPE_COMPETENCY
;
40 /* @var string a required param */
41 public $required_param = 'competency';
42 /* @var array no optional params */
43 public $optional_params = [];
47 * Get criteria details for displaying to users
48 * @param string $short Print short version of criteria
51 public function get_details($short = '') {
54 foreach ($this->params
as $p) {
55 $competency = new \core_competency\
competency($p['competency']);
57 $competency->set('description', '');
59 // Render the competency even if competencies are not currently enabled.
60 \core_competency\api
::skip_enabled();
61 if ($pluginsfunction = get_plugins_with_function('render_competency_summary')) {
62 foreach ($pluginsfunction as $plugintype => $plugins) {
63 foreach ($plugins as $pluginfunction) {
64 $output[] = $pluginfunction($competency, $competency->get_framework(), false, false, true);
68 \core_competency\api
::check_enabled();
71 return '<dl><dd class="p-3 mb-2 bg-light text-dark border">' .
72 implode('</dd><dd class="p-3 mb-2 bg-light text-dark border">', $output) .
77 * Add appropriate new criteria options to the form
78 * @param object $mform moodle form
79 * @return array First item is a boolean to indicate an error and the second is the error message.
81 public function get_options(&$mform) {
84 $availablebadges = null;
86 $mform->addElement('header', 'first_header', $this->get_title());
87 $mform->addHelpButton('first_header', 'criteria_' . $this->criteriatype
, 'badges');
89 // Determine if this badge is a course badge or a site badge.
91 if (count($this->params
)) {
92 $competencies = implode(',', array_keys($this->params
));
94 $badge = $DB->get_record('badge', array('id' => $this->badgeid
));
98 if ($badge->type
== BADGE_TYPE_SITE
) {
99 $context = context_system
::instance();
101 } else if ($badge->type
== BADGE_TYPE_COURSE
) {
102 $context = context_course
::instance($badge->courseid
);
103 $courseid = $badge->courseid
;
105 if ($pluginsfunction = get_plugins_with_function('competency_picker')) {
106 foreach ($pluginsfunction as $plugintype => $plugins) {
107 foreach ($plugins as $pluginfunction) {
108 $output[] = $pluginfunction($mform, $courseid, $context, 'competency_competencies');
112 $mform->getElement('competency_competencies')->setValue($competencies);
113 $mform->addRule('competency_competencies', get_string('requiredcompetency', 'badges'), 'required');
117 $mform->addElement('header', 'aggregation', get_string('method', 'badges'));
119 $agg[] =& $mform->createElement('radio', 'agg', '', get_string('allmethodcompetencies', 'badges'), 1);
120 $agg[] =& $mform->createElement('radio', 'agg', '', get_string('anymethodcompetencies', 'badges'), 2);
121 $mform->addGroup($agg, 'methodgr', '', array('<br/>'), false);
122 if ($this->id
!== 0) {
123 $mform->setDefault('agg', $this->method
);
125 $mform->setDefault('agg', BADGE_CRITERIA_AGGREGATION_ANY
);
129 return array($none, get_string('noparamstoadd', 'badges'));
133 * Save criteria records
135 * @param array $params Values from the form or any other array.
137 public function save($params = array()) {
138 $competencies = $params['competency_competencies'];
139 unset($params['competency_competencies']);
140 if (is_string($competencies)) {
141 $competencies = explode(',', $competencies);
143 foreach ($competencies as $competencyid) {
144 $params["competency_{$competencyid}"] = $competencyid;
146 parent
::save($params);
150 * Review this criteria and decide if it has been completed
152 * @param int $userid User whose criteria completion needs to be reviewed.
153 * @param bool $filtered An additional parameter indicating that user list
154 * has been reduced and some expensive checks can be skipped.
156 * @return bool Whether criteria is complete.
158 public function review($userid, $filtered = false) {
164 if (!self
::is_enabled()) {
167 foreach ($this->params
as $param) {
168 $competencyids[] = $param['competency'];
172 $badge = $DB->get_record('badge', array('id' => $this->badgeid
));
173 if ($badge->type
== BADGE_TYPE_SITE
) {
174 $existing = \core_competency\user_competency
::get_multiple($userid, $competencyids);
175 } else if ($badge->type
== BADGE_TYPE_COURSE
) {
176 $existing = \core_competency\user_competency_course
::get_multiple($userid, $badge->courseid
, $competencyids);
179 if ($this->method
== BADGE_CRITERIA_AGGREGATION_ALL
) {
180 // Any vs all conditions are reversed when no criteria let us finish early.
184 foreach ($this->params
as $param) {
185 $proficiency = false;
186 foreach ($existing as $usercompetency) {
187 if ($usercompetency->get('competencyid') == $param['competency']) {
188 $proficiency = $usercompetency->get('proficiency');
192 if ($this->method
== BADGE_CRITERIA_AGGREGATION_ALL
) {
196 } else if ($this->method
== BADGE_CRITERIA_AGGREGATION_ANY
) {
207 * Returns array with sql code and parameters returning all ids
208 * of users who meet this particular criterion.
210 * @return array list($join, $where, $params)
212 public function get_completed_criteria_sql() {
220 $badge = $DB->get_record('badge', array('id' => $this->badgeid
));
222 if (!self
::is_enabled()) {
223 return array($join, $where, $params);
226 if ($this->method
== BADGE_CRITERIA_AGGREGATION_ANY
) {
227 // User has received ANY of the required competencies (we can use an in or equals list).
228 foreach ($this->params
as $param) {
229 $competencyids[] = $param['competency'];
232 $where = ' AND uc2.competencyid ';
233 list($sql, $params) = $DB->get_in_or_equal($competencyids, SQL_PARAMS_NAMED
, 'usercomp');
235 if ($badge->type
== BADGE_TYPE_SITE
) {
236 $join = ' JOIN {competency_usercomp} uc2 ON uc2.userid = u.id';
237 } else if ($badge->type
== BADGE_TYPE_COURSE
) {
238 $join = ' JOIN {competency_usercompcourse} uc2 ON uc2.userid = u.id AND uc2.courseid = :competencycourseid ';
239 $params['competencycourseid'] = $badge->courseid
;
241 $where .= ' AND uc2.proficiency = :isproficient ';
242 $params['isproficient'] = true;
245 // User has received ALL of the required competencies (we have to join on each one).
247 foreach ($this->params
as $param) {
249 $join .= ' JOIN {competency_usercomp} uc' . $joincount . ' ON uc' . $joincount . '.userid = u.id';
250 $where .= ' AND uc' . $joincount . '.competencyid = :competencyindex' . $joincount;
251 $params['competencyindex' . $joincount] = $param['competency'];
253 $where .= ' AND uc' . $joincount . '.userid = u.id';
254 $where .= ' AND uc' . $joincount . '.proficiency = :isproficient' . $joincount;
255 $params['isproficient' . $joincount] = true;
259 return array($join, $where, $params);
263 * Hide this criteria when competencies are disabled.
267 public static function is_enabled() {
268 return \core_competency\api
::is_enabled();
272 * Check if any badge has records for competencies.
274 * @param array $competencyids Array of competencies ids.
275 * @return boolean Return true if competencies were found in any badge.
277 public static function has_records_for_competencies($competencyids) {
279 list($insql, $params) = $DB->get_in_or_equal($competencyids, SQL_PARAMS_NAMED
);
280 $sql = "SELECT DISTINCT bc.badgeid
281 FROM {badge_criteria} bc
282 JOIN {badge_criteria_param} bcp ON bc.id = bcp.critid
283 WHERE bc.criteriatype = :criteriatype AND value $insql";
284 $params['criteriatype'] = BADGE_CRITERIA_TYPE_COMPETENCY
;
286 return self
::record_exists_sql($sql, $params);