mirror of
https://github.com/moodle/moodle.git
synced 2025-04-21 16:32:18 +02:00
MDL-42965 badges: Improve badge criteria review performance
This commit is contained in:
parent
9b37cd72a2
commit
c8d2f392c5
@ -236,9 +236,20 @@ abstract class award_criteria {
|
||||
* Review this criteria and decide if the user has completed
|
||||
*
|
||||
* @param int $userid User whose criteria completion needs to be reviewed.
|
||||
* @param bool $filtered An additional parameter indicating that user list
|
||||
* has been reduced and some expensive checks can be skipped.
|
||||
*
|
||||
* @return bool Whether criteria is complete
|
||||
*/
|
||||
abstract public function review($userid);
|
||||
abstract public function review($userid, $filtered = false);
|
||||
|
||||
/**
|
||||
* Returns array with sql code and parameters returning all ids
|
||||
* of users who meet this particular criterion.
|
||||
*
|
||||
* @return array list($join, $where, $params)
|
||||
*/
|
||||
abstract public function get_completed_criteria_sql();
|
||||
|
||||
/**
|
||||
* Mark this criteria as complete for a user
|
||||
|
@ -37,13 +37,20 @@ class award_criteria_activity extends award_criteria {
|
||||
public $criteriatype = BADGE_CRITERIA_TYPE_ACTIVITY;
|
||||
|
||||
private $courseid;
|
||||
private $coursestartdate;
|
||||
|
||||
public $required_param = 'module';
|
||||
public $optional_params = array('bydate');
|
||||
|
||||
public function __construct($record) {
|
||||
global $DB;
|
||||
parent::__construct($record);
|
||||
$this->courseid = self::get_course();
|
||||
|
||||
$course = $DB->get_record_sql('SELECT b.courseid, c.startdate
|
||||
FROM {badge} b INNER JOIN {course} c ON b.courseid = c.id
|
||||
WHERE b.id = :badgeid ', array('badgeid' => $this->badgeid));
|
||||
$this->courseid = $course->courseid;
|
||||
$this->coursestartdate = $course->startdate;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -95,17 +102,6 @@ class award_criteria_activity extends award_criteria {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return course ID for activities
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function get_course() {
|
||||
global $DB;
|
||||
$courseid = $DB->get_field('badge', 'courseid', array('id' => $this->badgeid));
|
||||
return $courseid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add appropriate new criteria options to the form
|
||||
*
|
||||
@ -184,14 +180,17 @@ class award_criteria_activity extends award_criteria {
|
||||
* Review this criteria and decide if it has been completed
|
||||
*
|
||||
* @param int $userid User whose criteria completion needs to be reviewed.
|
||||
* @param bool $filtered An additional parameter indicating that user list
|
||||
* has been reduced and some expensive checks can be skipped.
|
||||
*
|
||||
* @return bool Whether criteria is complete
|
||||
*/
|
||||
public function review($userid) {
|
||||
global $DB;
|
||||
public function review($userid, $filtered = false) {
|
||||
$completionstates = array(COMPLETION_COMPLETE, COMPLETION_COMPLETE_PASS);
|
||||
$course = $DB->get_record('course', array('id' => $this->courseid));
|
||||
$course = new stdClass();
|
||||
$course->id = $this->courseid;
|
||||
|
||||
if ($course->startdate > time()) {
|
||||
if ($this->coursestartdate > time()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -217,7 +216,7 @@ class award_criteria_activity extends award_criteria {
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else if ($this->method == BADGE_CRITERIA_AGGREGATION_ANY) {
|
||||
} else {
|
||||
if (in_array($data->completionstate, $completionstates) && $check_date) {
|
||||
return true;
|
||||
} else {
|
||||
@ -229,4 +228,44 @@ class award_criteria_activity extends award_criteria {
|
||||
|
||||
return $overall;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns array with sql code and parameters returning all ids
|
||||
* of users who meet this particular criterion.
|
||||
*
|
||||
* @return array list($join, $where, $params)
|
||||
*/
|
||||
public function get_completed_criteria_sql() {
|
||||
$join = '';
|
||||
$where = '';
|
||||
$params = array();
|
||||
|
||||
if ($this->method == BADGE_CRITERIA_AGGREGATION_ANY) {
|
||||
foreach ($this->params as $param) {
|
||||
$moduledata[] = " cmc.coursemoduleid = :completedmodule{$param['module']} ";
|
||||
$params["completedmodule{$param['module']}"] = $param['module'];
|
||||
}
|
||||
if (!empty($moduledata)) {
|
||||
$extraon = implode(' OR ', $moduledata);
|
||||
$join = " JOIN {course_modules_completion} cmc ON cmc.userid = u.id AND
|
||||
( cmc.completionstate = :completionpass OR cmc.completionstate = :completioncomplete ) AND ({$extraon})";
|
||||
$params["completionpass"] = COMPLETION_COMPLETE_PASS;
|
||||
$params["completioncomplete"] = COMPLETION_COMPLETE;
|
||||
}
|
||||
return array($join, $where, $params);
|
||||
} else {
|
||||
foreach ($this->params as $param) {
|
||||
$join .= " LEFT JOIN {course_modules_completion} cmc{$param['module']} ON
|
||||
cmc{$param['module']}.userid = u.id AND
|
||||
cmc{$param['module']}.coursemoduleid = :completedmodule{$param['module']} AND
|
||||
( cmc{$param['module']}.completionstate = :completionpass{$param['module']} OR
|
||||
cmc{$param['module']}.completionstate = :completioncomplete{$param['module']} )";
|
||||
$where .= " AND cmc{$param['module']}.coursemoduleid IS NOT NULL ";
|
||||
$params["completedmodule{$param['module']}"] = $param['module'];
|
||||
$params["completionpass{$param['module']}"] = COMPLETION_COMPLETE_PASS;
|
||||
$params["completioncomplete{$param['module']}"] = COMPLETION_COMPLETE;
|
||||
}
|
||||
return array($join, $where, $params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -38,9 +38,23 @@ class award_criteria_course extends award_criteria {
|
||||
/* @var int Criteria [BADGE_CRITERIA_TYPE_COURSE] */
|
||||
public $criteriatype = BADGE_CRITERIA_TYPE_COURSE;
|
||||
|
||||
private $courseid;
|
||||
private $coursestartdate;
|
||||
|
||||
public $required_param = 'course';
|
||||
public $optional_params = array('grade', 'bydate');
|
||||
|
||||
public function __construct($record) {
|
||||
global $DB;
|
||||
parent::__construct($record);
|
||||
|
||||
$course = $DB->get_record_sql('SELECT b.courseid, c.startdate
|
||||
FROM {badge} b INNER JOIN {course} c ON b.courseid = c.id
|
||||
WHERE b.id = :badgeid ', array('badgeid' => $this->badgeid));
|
||||
$this->courseid = $course->courseid;
|
||||
$this->coursestartdate = $course->startdate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add appropriate form elements to the criteria form
|
||||
*
|
||||
@ -151,18 +165,22 @@ class award_criteria_course extends award_criteria {
|
||||
* Review this criteria and decide if it has been completed
|
||||
*
|
||||
* @param int $userid User whose criteria completion needs to be reviewed.
|
||||
* @param bool $filtered An additional parameter indicating that user list
|
||||
* has been reduced and some expensive checks can be skipped.
|
||||
*
|
||||
* @return bool Whether criteria is complete
|
||||
*/
|
||||
public function review($userid) {
|
||||
global $DB;
|
||||
public function review($userid, $filtered = false) {
|
||||
$course = new stdClass();
|
||||
$course->id = $this->courseid;
|
||||
|
||||
if ($this->coursestartdate > time()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$info = new completion_info($course);
|
||||
|
||||
foreach ($this->params as $param) {
|
||||
$course = $DB->get_record('course', array('id' => $param['course']));
|
||||
|
||||
if ($course->startdate > time()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$info = new completion_info($course);
|
||||
$check_grade = true;
|
||||
$check_date = true;
|
||||
|
||||
@ -171,7 +189,7 @@ class award_criteria_course extends award_criteria {
|
||||
$check_grade = ($grade->grade >= $param['grade']);
|
||||
}
|
||||
|
||||
if (isset($param['bydate'])) {
|
||||
if (!$filtered && isset($param['bydate'])) {
|
||||
$cparams = array(
|
||||
'userid' => $userid,
|
||||
'course' => $course->id,
|
||||
@ -188,4 +206,27 @@ class award_criteria_course extends award_criteria {
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns array with sql code and parameters returning all ids
|
||||
* of users who meet this particular criterion.
|
||||
*
|
||||
* @return array list($join, $where, $params)
|
||||
*/
|
||||
public function get_completed_criteria_sql() {
|
||||
// We have only one criterion here, so taking the first one.
|
||||
$coursecriteria = reset($this->params);
|
||||
|
||||
$join = " LEFT JOIN {course_completions} cc ON cc.userid = u.id AND cc.timecompleted > 0";
|
||||
$where = ' AND cc.course = :courseid ';
|
||||
$params['courseid'] = $this->courseid;
|
||||
|
||||
// Add by date parameter.
|
||||
if (isset($param['bydate'])) {
|
||||
$where .= ' AND cc.timecompleted <= :completebydate';
|
||||
$params['completebydate'] = $coursecriteria['bydate'];
|
||||
}
|
||||
|
||||
return array($join, $where, $params);
|
||||
}
|
||||
}
|
||||
|
@ -202,12 +202,17 @@ class award_criteria_courseset extends award_criteria {
|
||||
/**
|
||||
* Review this criteria and decide if it has been completed
|
||||
*
|
||||
* @param int $userid User whose criteria completion needs to be reviewed.
|
||||
* @param bool $filtered An additional parameter indicating that user list
|
||||
* has been reduced and some expensive checks can be skipped.
|
||||
*
|
||||
* @return bool Whether criteria is complete
|
||||
*/
|
||||
public function review($userid) {
|
||||
global $DB;
|
||||
public function review($userid, $filtered = false) {
|
||||
foreach ($this->params as $param) {
|
||||
$course = $DB->get_record('course', array('id' => $param['course']));
|
||||
$course = new stdClass();
|
||||
$course->id = $param['course'];
|
||||
|
||||
$info = new completion_info($course);
|
||||
$check_grade = true;
|
||||
$check_date = true;
|
||||
@ -217,7 +222,7 @@ class award_criteria_courseset extends award_criteria {
|
||||
$check_grade = ($grade->grade >= $param['grade']);
|
||||
}
|
||||
|
||||
if (isset($param['bydate'])) {
|
||||
if (!$filtered && isset($param['bydate'])) {
|
||||
$cparams = array(
|
||||
'userid' => $userid,
|
||||
'course' => $course->id,
|
||||
@ -235,7 +240,7 @@ class award_criteria_courseset extends award_criteria {
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else if ($this->method == BADGE_CRITERIA_AGGREGATION_ANY) {
|
||||
} else {
|
||||
if ($info->is_course_complete($userid) && $check_grade && $check_date) {
|
||||
return true;
|
||||
} else {
|
||||
@ -247,4 +252,39 @@ class award_criteria_courseset extends award_criteria {
|
||||
|
||||
return $overall;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns array with sql code and parameters returning all ids
|
||||
* of users who meet this particular criterion.
|
||||
*
|
||||
* @return array list($join, $where, $params)
|
||||
*/
|
||||
public function get_completed_criteria_sql() {
|
||||
$join = '';
|
||||
$where = '';
|
||||
$params = array();
|
||||
|
||||
if ($this->method == BADGE_CRITERIA_AGGREGATION_ANY) {
|
||||
foreach ($this->params as $param) {
|
||||
$coursedata[] = " cc.course = :completedcourse{$param['course']} ";
|
||||
$params["completedcourse{$param['course']}"] = $param['course'];
|
||||
}
|
||||
if (!empty($coursedata)) {
|
||||
$extraon = implode(' OR ', $coursedata);
|
||||
$join = " JOIN {course_completions} cc ON cc.userid = u.id AND
|
||||
cc.timecompleted > 0 AND ({$extraon})";
|
||||
}
|
||||
return array($join, $where, $params);
|
||||
} else {
|
||||
foreach ($this->params as $param) {
|
||||
$join .= " LEFT JOIN {course_completions} cc{$param['course']} ON
|
||||
cc{$param['course']}.userid = u.id AND
|
||||
cc{$param['course']}.course = :completedcourse{$param['course']} AND
|
||||
cc{$param['course']}.timecompleted > 0 ";
|
||||
$where .= " AND cc{$param['course']}.course IS NOT NULL ";
|
||||
$params["completedcourse{$param['course']}"] = $param['course'];
|
||||
}
|
||||
return array($join, $where, $params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -142,11 +142,19 @@ class award_criteria_manual extends award_criteria {
|
||||
* Review this criteria and decide if it has been completed
|
||||
*
|
||||
* @param int $userid User whose criteria completion needs to be reviewed.
|
||||
* @param bool $filtered An additional parameter indicating that user list
|
||||
* has been reduced and some expensive checks can be skipped.
|
||||
*
|
||||
* @return bool Whether criteria is complete
|
||||
*/
|
||||
public function review($userid) {
|
||||
public function review($userid, $filtered = false) {
|
||||
global $DB;
|
||||
|
||||
// Users were already filtered by criteria completion.
|
||||
if ($filtered) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$overall = false;
|
||||
foreach ($this->params as $param) {
|
||||
$crit = $DB->get_record('badge_manual_award', array('issuerrole' => $param['role'], 'recipientid' => $userid, 'badgeid' => $this->badgeid));
|
||||
@ -157,7 +165,7 @@ class award_criteria_manual extends award_criteria {
|
||||
$overall = true;
|
||||
continue;
|
||||
}
|
||||
} else if ($this->method == BADGE_CRITERIA_AGGREGATION_ANY) {
|
||||
} else {
|
||||
if (!$crit) {
|
||||
$overall = false;
|
||||
continue;
|
||||
@ -169,6 +177,41 @@ class award_criteria_manual extends award_criteria {
|
||||
return $overall;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns array with sql code and parameters returning all ids
|
||||
* of users who meet this particular criterion.
|
||||
*
|
||||
* @return array list($join, $where, $params)
|
||||
*/
|
||||
public function get_completed_criteria_sql() {
|
||||
$join = '';
|
||||
$where = '';
|
||||
$params = array();
|
||||
|
||||
if ($this->method == BADGE_CRITERIA_AGGREGATION_ANY) {
|
||||
foreach ($this->params as $param) {
|
||||
$roledata[] = " bma.issuerrole = :issuerrole{$param['role']} ";
|
||||
$params["issuerrole{$param['role']}"] = $param['role'];
|
||||
}
|
||||
if (!empty($roledata)) {
|
||||
$extraon = implode(' OR ', $roledata);
|
||||
$join = " JOIN {badge_manual_award} bma ON bma.recipientid = u.id
|
||||
AND bma.badgeid = :badgeid{$this->badgeid} AND ({$extraon})";
|
||||
$params["badgeid{$this->badgeid}"] = $this->badgeid;
|
||||
}
|
||||
return array($join, $where, $params);
|
||||
} else {
|
||||
foreach ($this->params as $param) {
|
||||
$join .= " LEFT JOIN {badge_manual_award} bma{$param['role']} ON
|
||||
bma{$param['role']}.recipientid = u.id AND
|
||||
bma{$param['role']}.issuerrole = :issuerrole{$param['role']} ";
|
||||
$where .= " AND bma{$param['role']}.issuerrole IS NOT NULL ";
|
||||
$params["issuerrole{$param['role']}"] = $param['role'];
|
||||
}
|
||||
return array($join, $where, $params);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete this criterion
|
||||
*
|
||||
|
@ -86,9 +86,12 @@ class award_criteria_overall extends award_criteria {
|
||||
* Overall criteria review should be called only from other criteria handlers.
|
||||
*
|
||||
* @param int $userid User whose criteria completion needs to be reviewed.
|
||||
* @param bool $filtered An additional parameter indicating that user list
|
||||
* has been reduced and some expensive checks can be skipped.
|
||||
*
|
||||
* @return bool Whether criteria is complete
|
||||
*/
|
||||
public function review($userid) {
|
||||
public function review($userid, $filtered = false) {
|
||||
global $DB;
|
||||
|
||||
$sql = "SELECT bc.*, bcm.critid, bcm.userid, bcm.datemet
|
||||
@ -114,7 +117,7 @@ class award_criteria_overall extends award_criteria {
|
||||
$overall = true;
|
||||
continue;
|
||||
}
|
||||
} else if ($this->method == BADGE_CRITERIA_AGGREGATION_ANY) {
|
||||
} else {
|
||||
if ($crit->datemet === null) {
|
||||
$overall = false;
|
||||
continue;
|
||||
@ -127,6 +130,16 @@ class award_criteria_overall extends award_criteria {
|
||||
return $overall;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns array with sql code and parameters returning all ids
|
||||
* of users who meet this particular criterion.
|
||||
*
|
||||
* @return array list($join, $where, $params)
|
||||
*/
|
||||
public function get_completed_criteria_sql() {
|
||||
return array('', '', array());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add appropriate criteria elements to the form
|
||||
*
|
||||
|
@ -156,35 +156,84 @@ class award_criteria_profile extends award_criteria {
|
||||
* Review this criteria and decide if it has been completed
|
||||
*
|
||||
* @param int $userid User whose criteria completion needs to be reviewed.
|
||||
* @param bool $filtered An additional parameter indicating that user list
|
||||
* has been reduced and some expensive checks can be skipped.
|
||||
*
|
||||
* @return bool Whether criteria is complete
|
||||
*/
|
||||
public function review($userid) {
|
||||
public function review($userid, $filtered = false) {
|
||||
global $DB;
|
||||
|
||||
$overall = false;
|
||||
// Users were already filtered by criteria completion, no checks required.
|
||||
if ($filtered) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$join = '';
|
||||
$where = '';
|
||||
$sqlparams = array();
|
||||
$rule = ($this->method == BADGE_CRITERIA_AGGREGATION_ANY) ? ' OR ' : ' AND ';
|
||||
|
||||
foreach ($this->params as $param) {
|
||||
if (is_numeric($param['field'])) {
|
||||
$crit = $DB->get_field('user_info_data', 'data', array('userid' => $userid, 'fieldid' => $param['field']));
|
||||
$infodata[] = " uid.fieldid = :fieldid{$param['field']} ";
|
||||
$sqlparams["fieldid{$param['field']}"] = $param['field'];
|
||||
} else {
|
||||
$crit = $DB->get_field('user', $param['field'], array('id' => $userid));
|
||||
}
|
||||
|
||||
if ($this->method == BADGE_CRITERIA_AGGREGATION_ALL) {
|
||||
if (!$crit) {
|
||||
return false;
|
||||
} else {
|
||||
$overall = true;
|
||||
continue;
|
||||
}
|
||||
} else if ($this->method == BADGE_CRITERIA_AGGREGATION_ANY) {
|
||||
if (!$crit) {
|
||||
$overall = false;
|
||||
continue;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
$userdata[] = " u.{$param['field']} != '' ";
|
||||
}
|
||||
}
|
||||
|
||||
// Add user custom field parameters if there are any.
|
||||
if (!empty($infodata)) {
|
||||
$extraon = implode($rule, $infodata);
|
||||
$join = " LEFT JOIN {user_info_data} uid ON uid.userid = u.id AND ({$extraon})";
|
||||
}
|
||||
|
||||
// Add user table field parameters if there are any.
|
||||
if (!empty($userdata)) {
|
||||
$extraon = implode($rule, $userdata);
|
||||
$where = " AND ({$extraon})";
|
||||
}
|
||||
|
||||
$sqlparams['userid'] = $userid;
|
||||
$sql = "SELECT u.* FROM {user} u " . $join . " WHERE u.id = :userid " . $where;
|
||||
$overall = $DB->record_exists_sql($sql, $sqlparams);
|
||||
|
||||
return $overall;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns array with sql code and parameters returning all ids
|
||||
* of users who meet this particular criterion.
|
||||
*
|
||||
* @return array list($join, $where, $params)
|
||||
*/
|
||||
public function get_completed_criteria_sql() {
|
||||
$join = '';
|
||||
$where = '';
|
||||
$params = array();
|
||||
$rule = ($this->method == BADGE_CRITERIA_AGGREGATION_ANY) ? ' OR ' : ' AND ';
|
||||
|
||||
foreach ($this->params as $param) {
|
||||
if (is_numeric($param['field'])) {
|
||||
$infodata[] = " uid.fieldid = :fieldid{$param['field']} ";
|
||||
$params["fieldid{$param['field']}"] = $param['field'];
|
||||
} else {
|
||||
$userdata[] = " u.{$param['field']} != '' ";
|
||||
}
|
||||
}
|
||||
|
||||
// Add user custom fields if there are any.
|
||||
if (!empty($infodata)) {
|
||||
$extraon = implode($rule, $infodata);
|
||||
$join = " LEFT JOIN {user_info_data} uid ON uid.userid = u.id AND ({$extraon})";
|
||||
}
|
||||
|
||||
// Add user table fields if there are any.
|
||||
if (!empty($userdata)) {
|
||||
$extraon = implode($rule, $userdata);
|
||||
$where = " AND ({$extraon})";
|
||||
}
|
||||
return array($join, $where, $params);
|
||||
}
|
||||
}
|
||||
|
@ -292,9 +292,10 @@ class core_badges_badgeslib_testcase extends advanced_testcase {
|
||||
$criteria_overall = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_OVERALL, 'badgeid' => $badge->id));
|
||||
$criteria_overall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY));
|
||||
$criteria_overall1 = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_PROFILE, 'badgeid' => $badge->id));
|
||||
$criteria_overall1->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ALL, 'field_address' => 'address'));
|
||||
$criteria_overall1->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ALL, 'field_address' => 'address', 'field_aim' => 'aim'));
|
||||
|
||||
$this->user->address = 'Test address';
|
||||
$this->user->aim = '999999999';
|
||||
$sink = $this->redirectEmails();
|
||||
user_update_user($this->user, false);
|
||||
$this->assertCount(1, $sink->get_messages());
|
||||
|
12
badges/upgrade.txt
Normal file
12
badges/upgrade.txt
Normal file
@ -0,0 +1,12 @@
|
||||
This files describes API changes in /badges/*,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
=== 2.7 ===
|
||||
|
||||
* get_completed_criteria_sql() - This method was added to award_criteria class and must be overriden
|
||||
in all criteria classes. This method returns an array consisting of SQL JOIN statement, WHERE conditions,
|
||||
and any parameters that might be required. The results are used in lib/badgeslib.php in review_all_criteria()
|
||||
to reduce to the minimum the number of users to review and award badges.
|
||||
|
||||
* New optional parameter $filtered in review() allows to indicate that some expensive checks can be skipped
|
||||
if the list of users has been initially filtered based on met criteria.
|
@ -429,51 +429,63 @@ class badge {
|
||||
set_time_limit(0);
|
||||
raise_memory_limit(MEMORY_HUGE);
|
||||
|
||||
// For site level badges, get all active site users who can earn this badge and haven't got it yet.
|
||||
if ($this->type == BADGE_TYPE_SITE) {
|
||||
$sql = 'SELECT DISTINCT u.id, bi.badgeid
|
||||
foreach ($this->criteria as $crit) {
|
||||
// Overall criterion is decided when other criteria are reviewed.
|
||||
if ($crit->criteriatype == BADGE_CRITERIA_TYPE_OVERALL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
list($extrajoin, $extrawhere, $extraparams) = $crit->get_completed_criteria_sql();
|
||||
// For site level badges, get all active site users who can earn this badge and haven't got it yet.
|
||||
if ($this->type == BADGE_TYPE_SITE) {
|
||||
$sql = "SELECT DISTINCT u.id, bi.badgeid
|
||||
FROM {user} u
|
||||
{$extrajoin}
|
||||
LEFT JOIN {badge_issued} bi
|
||||
ON u.id = bi.userid AND bi.badgeid = :badgeid
|
||||
WHERE bi.badgeid IS NULL AND u.id != :guestid AND u.deleted = 0';
|
||||
$toearn = $DB->get_fieldset_sql($sql, array('badgeid' => $this->id, 'guestid' => $CFG->siteguest));
|
||||
} else {
|
||||
// For course level badges, get users who can earn this badge in the course.
|
||||
// These are all enrolled users with capability moodle/badges:earnbadge.
|
||||
$earned = $DB->get_fieldset_select('badge_issued', 'userid AS id', 'badgeid = :badgeid', array('badgeid' => $this->id));
|
||||
$users = get_enrolled_users($this->get_context(), 'moodle/badges:earnbadge', 0, 'u.id');
|
||||
$toearn = array_diff(array_keys($users), $earned);
|
||||
}
|
||||
|
||||
foreach ($toearn as $uid) {
|
||||
$toreview = false;
|
||||
foreach ($this->criteria as $crit) {
|
||||
if ($crit->criteriatype != BADGE_CRITERIA_TYPE_OVERALL) {
|
||||
if ($crit->review($uid)) {
|
||||
$crit->mark_complete($uid);
|
||||
if ($this->criteria[BADGE_CRITERIA_TYPE_OVERALL]->method == BADGE_CRITERIA_AGGREGATION_ANY) {
|
||||
$this->criteria[BADGE_CRITERIA_TYPE_OVERALL]->mark_complete($uid);
|
||||
$this->issue($uid);
|
||||
$awards++;
|
||||
break;
|
||||
} else {
|
||||
$toreview = true;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if ($this->criteria[BADGE_CRITERIA_TYPE_OVERALL]->method == BADGE_CRITERIA_AGGREGATION_ANY) {
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
WHERE bi.badgeid IS NULL AND u.id != :guestid AND u.deleted = 0 " . $extrawhere;
|
||||
$params = array_merge(array('badgeid' => $this->id, 'guestid' => $CFG->siteguest), $extraparams);
|
||||
$toearn = $DB->get_fieldset_sql($sql, $params);
|
||||
} else {
|
||||
// For course level badges, get all users who already earned the badge in this course.
|
||||
// Then find the ones who are enrolled in the course and don't have a badge yet.
|
||||
$earned = $DB->get_fieldset_select('badge_issued', 'userid AS id', 'badgeid = :badgeid', array('badgeid' => $this->id));
|
||||
$wheresql = '';
|
||||
$earnedparams = array();
|
||||
if (!empty($earned)) {
|
||||
list($earnedsql, $earnedparams) = $DB->get_in_or_equal($earned, SQL_PARAMS_NAMED, 'u', false);
|
||||
$wheresql = ' WHERE u.id ' . $earnedsql;
|
||||
}
|
||||
list($enrolledsql, $enrolledparams) = get_enrolled_sql($this->get_context(), 'moodle/badges:earnbadge', 0, true);
|
||||
$sql = "SELECT u.id
|
||||
FROM {user} u
|
||||
{$extrajoin}
|
||||
JOIN ({$enrolledsql}) je ON je.id = u.id " . $wheresql . $extrawhere;
|
||||
$params = array_merge($enrolledparams, $earnedparams, $extraparams);
|
||||
$toearn = $DB->get_fieldset_sql($sql, $params);
|
||||
}
|
||||
// Review overall if it is required.
|
||||
if ($toreview && $this->criteria[BADGE_CRITERIA_TYPE_OVERALL]->review($uid)) {
|
||||
$this->criteria[BADGE_CRITERIA_TYPE_OVERALL]->mark_complete($uid);
|
||||
$this->issue($uid);
|
||||
$awards++;
|
||||
|
||||
foreach ($toearn as $uid) {
|
||||
$reviewoverall = false;
|
||||
if ($crit->review($uid, true)) {
|
||||
$crit->mark_complete($uid);
|
||||
if ($this->criteria[BADGE_CRITERIA_TYPE_OVERALL]->method == BADGE_CRITERIA_AGGREGATION_ANY) {
|
||||
$this->criteria[BADGE_CRITERIA_TYPE_OVERALL]->mark_complete($uid);
|
||||
$this->issue($uid);
|
||||
$awards++;
|
||||
} else {
|
||||
$reviewoverall = true;
|
||||
}
|
||||
} else {
|
||||
// Will be reviewed some other time.
|
||||
$reviewoverall = false;
|
||||
}
|
||||
// Review overall if it is required.
|
||||
if ($reviewoverall && $this->criteria[BADGE_CRITERIA_TYPE_OVERALL]->review($uid)) {
|
||||
$this->criteria[BADGE_CRITERIA_TYPE_OVERALL]->mark_complete($uid);
|
||||
$this->issue($uid);
|
||||
$awards++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user