Skip to content

Commit

Permalink
MDL-42965 badges: Improve badge criteria review performance
Browse files Browse the repository at this point in the history
  • Loading branch information
Yuliya Bozhko committed Dec 5, 2013
1 parent 9b37cd7 commit c8d2f39
Show file tree
Hide file tree
Showing 10 changed files with 356 additions and 95 deletions.
13 changes: 12 additions & 1 deletion badges/criteria/award_criteria.php
Original file line number Diff line number Diff line change
Expand Up @@ -236,9 +236,20 @@ public function config_form_criteria($data) {
* 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
Expand Down
73 changes: 56 additions & 17 deletions badges/criteria/award_criteria_activity.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

/**
Expand Down Expand Up @@ -95,17 +102,6 @@ public function get_details($short = '') {
}
}

/**
* 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
*
Expand Down Expand Up @@ -184,14 +180,17 @@ public function get_options(&$mform) {
* 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;
}

Expand All @@ -217,7 +216,7 @@ public function review($userid) {
} else {
return false;
}
} else if ($this->method == BADGE_CRITERIA_AGGREGATION_ANY) {
} else {
if (in_array($data->completionstate, $completionstates) && $check_date) {
return true;
} else {
Expand All @@ -229,4 +228,44 @@ public function review($userid) {

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);
}
}
}
61 changes: 51 additions & 10 deletions badges/criteria/award_criteria_course.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand Down Expand Up @@ -151,18 +165,22 @@ public function get_options(&$mform) {
* 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;
foreach ($this->params as $param) {
$course = $DB->get_record('course', array('id' => $param['course']));
public function review($userid, $filtered = false) {
$course = new stdClass();
$course->id = $this->courseid;

if ($course->startdate > time()) {
return false;
}
if ($this->coursestartdate > time()) {
return false;
}

$info = new completion_info($course);
$info = new completion_info($course);

foreach ($this->params as $param) {
$check_grade = true;
$check_date = true;

Expand All @@ -171,7 +189,7 @@ public function review($userid) {
$check_grade = ($grade->grade >= $param['grade']);
}

if (isset($param['bydate'])) {
if (!$filtered && isset($param['bydate'])) {
$cparams = array(
'userid' => $userid,
'course' => $course->id,
Expand All @@ -188,4 +206,27 @@ public function review($userid) {

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);
}
}
50 changes: 45 additions & 5 deletions badges/criteria/award_criteria_courseset.php
Original file line number Diff line number Diff line change
Expand Up @@ -202,12 +202,17 @@ public function get_options(&$mform) {
/**
* 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;
Expand All @@ -217,7 +222,7 @@ public function review($userid) {
$check_grade = ($grade->grade >= $param['grade']);
}

if (isset($param['bydate'])) {
if (!$filtered && isset($param['bydate'])) {
$cparams = array(
'userid' => $userid,
'course' => $course->id,
Expand All @@ -235,7 +240,7 @@ public function review($userid) {
} 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 {
Expand All @@ -247,4 +252,39 @@ public function review($userid) {

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);
}
}
}
47 changes: 45 additions & 2 deletions badges/criteria/award_criteria_manual.php
Original file line number Diff line number Diff line change
Expand Up @@ -142,11 +142,19 @@ public function get_details($short = '') {
* 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));
Expand All @@ -157,7 +165,7 @@ public function review($userid) {
$overall = true;
continue;
}
} else if ($this->method == BADGE_CRITERIA_AGGREGATION_ANY) {
} else {
if (!$crit) {
$overall = false;
continue;
Expand All @@ -169,6 +177,41 @@ public function review($userid) {
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
*
Expand Down
Loading

0 comments on commit c8d2f39

Please sign in to comment.