Skip to content

Commit

Permalink
MDL-52206 core: Update new activity_custom_completion
Browse files Browse the repository at this point in the history
Update the custom_completion classes to accept the new completion
criteria
  • Loading branch information
Peter Dias committed Oct 4, 2021
1 parent d975251 commit 2c7893c
Show file tree
Hide file tree
Showing 12 changed files with 178 additions and 90 deletions.
7 changes: 6 additions & 1 deletion completion/classes/activity_custom_completion.php
Expand Up @@ -40,15 +40,20 @@ abstract class activity_custom_completion {
/** @var int The user's ID. */
protected $userid;

/** @var array The current state of core completion */
protected $completionstate;

/**
* activity_custom_completion constructor.
*
* @param cm_info $cm
* @param int $userid
* @param array|null $completionstate The current state of the core completion criteria
*/
public function __construct(cm_info $cm, int $userid) {
public function __construct(cm_info $cm, int $userid, ?array $completionstate = null) {
$this->cm = $cm;
$this->userid = $userid;
$this->completionstate = $completionstate;
}

/**
Expand Down
13 changes: 12 additions & 1 deletion completion/classes/cm_completion_details.php
Expand Up @@ -73,7 +73,11 @@ public function __construct(completion_info $completioninfo, cm_info $cminfo, in
$this->returndetails = $returndetails;
$cmcompletionclass = activity_custom_completion::get_cm_completion_class($this->cminfo->modname);
if ($cmcompletionclass) {
$this->cmcompletion = new $cmcompletionclass($this->cminfo, $this->userid);
$this->cmcompletion = new $cmcompletionclass(
$this->cminfo,
$this->userid,
$completioninfo->get_core_completion_state($cminfo, $userid)
);
}
}

Expand Down Expand Up @@ -128,6 +132,13 @@ public function get_details(): array {
'status' => $status,
'description' => get_string('detail_desc:receivegrade', 'completion'),
];

if (!is_null($this->cminfo->completionpassgrade) && $this->cminfo->completionpassgrade) {
$details['completionpassgrade'] = (object)[
'status' => $completiondata->passgrade ?? COMPLETION_INCOMPLETE,
'description' => get_string('detail_desc:receivepassgrade', 'completion'),
];
}
}

if ($this->cmcompletion) {
Expand Down
83 changes: 73 additions & 10 deletions completion/tests/cm_completion_details_test.php
Expand Up @@ -93,6 +93,7 @@ protected function setup_data(?int $completion, array $completionoptions = [],
['modname', $modname],
['completionview', $completionoptions['completionview'] ?? COMPLETION_VIEW_NOT_REQUIRED],
['completiongradeitemnumber', $completionoptions['completionusegrade'] ?? null],
['completionpassgrade', $completionoptions['completionpassgrade'] ?? null],
]));

return new cm_completion_details($this->completioninfo, $mockcminfo, 2);
Expand Down Expand Up @@ -192,45 +193,45 @@ public function test_get_overall_completion(int $state) {
public function get_details_provider() {
return [
'No completion tracking' => [
COMPLETION_TRACKING_NONE, null, null, []
COMPLETION_TRACKING_NONE, null, null, null, []
],
'Manual completion tracking' => [
COMPLETION_TRACKING_MANUAL, null, null, []
COMPLETION_TRACKING_MANUAL, null, null, null, []
],
'Automatic, require view, not viewed' => [
COMPLETION_TRACKING_AUTOMATIC, COMPLETION_INCOMPLETE, null, [
COMPLETION_TRACKING_AUTOMATIC, COMPLETION_INCOMPLETE, null, null, [
'completionview' => (object)[
'status' => COMPLETION_INCOMPLETE,
'description' => get_string('detail_desc:view', 'completion'),
]
]
],
'Automatic, require view, viewed' => [
COMPLETION_TRACKING_AUTOMATIC, COMPLETION_COMPLETE, null, [
COMPLETION_TRACKING_AUTOMATIC, COMPLETION_COMPLETE, null, null, [
'completionview' => (object)[
'status' => COMPLETION_COMPLETE,
'description' => get_string('detail_desc:view', 'completion'),
]
]
],
'Automatic, require grade, incomplete' => [
COMPLETION_TRACKING_AUTOMATIC, null, COMPLETION_INCOMPLETE, [
COMPLETION_TRACKING_AUTOMATIC, null, COMPLETION_INCOMPLETE, null, [
'completionusegrade' => (object)[
'status' => COMPLETION_INCOMPLETE,
'description' => get_string('detail_desc:receivegrade', 'completion'),
]
]
],
'Automatic, require grade, complete' => [
COMPLETION_TRACKING_AUTOMATIC, null, COMPLETION_COMPLETE, [
COMPLETION_TRACKING_AUTOMATIC, null, COMPLETION_COMPLETE, null, [
'completionusegrade' => (object)[
'status' => COMPLETION_COMPLETE,
'description' => get_string('detail_desc:receivegrade', 'completion'),
]
]
],
'Automatic, require view (complete) and grade (incomplete)' => [
COMPLETION_TRACKING_AUTOMATIC, COMPLETION_COMPLETE, COMPLETION_INCOMPLETE, [
COMPLETION_TRACKING_AUTOMATIC, COMPLETION_COMPLETE, COMPLETION_INCOMPLETE, null, [
'completionview' => (object)[
'status' => COMPLETION_COMPLETE,
'description' => get_string('detail_desc:view', 'completion'),
Expand All @@ -242,7 +243,7 @@ public function get_details_provider() {
]
],
'Automatic, require view (incomplete) and grade (complete)' => [
COMPLETION_TRACKING_AUTOMATIC, COMPLETION_INCOMPLETE, COMPLETION_COMPLETE, [
COMPLETION_TRACKING_AUTOMATIC, COMPLETION_INCOMPLETE, COMPLETION_COMPLETE, null, [
'completionview' => (object)[
'status' => COMPLETION_INCOMPLETE,
'description' => get_string('detail_desc:view', 'completion'),
Expand All @@ -253,6 +254,62 @@ public function get_details_provider() {
]
]
],
'Automatic, require grade, require pass grade, complete' => [
COMPLETION_TRACKING_AUTOMATIC, null, COMPLETION_COMPLETE, COMPLETION_COMPLETE, [
'completionusegrade' => (object)[
'status' => COMPLETION_COMPLETE,
'description' => get_string('detail_desc:receivegrade', 'completion'),
],
'completionpassgrade' => (object)[
'status' => COMPLETION_COMPLETE,
'description' => get_string('detail_desc:receivepassgrade', 'completion'),
],
]
],
'Automatic, require grade, require pass grade, incomplete' => [
COMPLETION_TRACKING_AUTOMATIC, null, COMPLETION_COMPLETE, COMPLETION_INCOMPLETE, [
'completionusegrade' => (object)[
'status' => COMPLETION_COMPLETE,
'description' => get_string('detail_desc:receivegrade', 'completion'),
],
'completionpassgrade' => (object)[
'status' => COMPLETION_INCOMPLETE,
'description' => get_string('detail_desc:receivepassgrade', 'completion'),
],
]
],
'Automatic, require view (complete), require grade(complete), require pass grade(complete)' => [
COMPLETION_TRACKING_AUTOMATIC, COMPLETION_COMPLETE, COMPLETION_COMPLETE, COMPLETION_COMPLETE, [
'completionview' => (object)[
'status' => COMPLETION_COMPLETE,
'description' => get_string('detail_desc:view', 'completion'),
],
'completionusegrade' => (object)[
'status' => COMPLETION_COMPLETE,
'description' => get_string('detail_desc:receivegrade', 'completion'),
],
'completionpassgrade' => (object)[
'status' => COMPLETION_COMPLETE,
'description' => get_string('detail_desc:receivepassgrade', 'completion'),
],
]
],
'Automatic, require view (incomplete), require grade(complete), require pass grade(complete)' => [
COMPLETION_TRACKING_AUTOMATIC, COMPLETION_INCOMPLETE, COMPLETION_COMPLETE, COMPLETION_COMPLETE, [
'completionview' => (object)[
'status' => COMPLETION_INCOMPLETE,
'description' => get_string('detail_desc:view', 'completion'),
],
'completionusegrade' => (object)[
'status' => COMPLETION_COMPLETE,
'description' => get_string('detail_desc:receivegrade', 'completion'),
],
'completionpassgrade' => (object)[
'status' => COMPLETION_COMPLETE,
'description' => get_string('detail_desc:receivepassgrade', 'completion'),
],
]
],
];
}

Expand All @@ -263,13 +320,16 @@ public function get_details_provider() {
* @param int $completion The completion tracking mode.
* @param int|null $completionview Completion status of the "view" completion condition.
* @param int|null $completiongrade Completion status of the "must receive grade" completion condition.
* @param int|null $completionpassgrade Completion status of the "must receive passing grade" completion condition.
* @param array $expecteddetails Expected completion details returned by get_details().
*/
public function test_get_details(int $completion, ?int $completionview, ?int $completiongrade, array $expecteddetails) {
public function test_get_details(int $completion, ?int $completionview,
?int $completiongrade, ?int $completionpassgrade, array $expecteddetails) {
$options = [];
$getdatareturn = (object)[
'viewed' => $completionview,
'completiongrade' => $completiongrade,
'passgrade' => $completionpassgrade,
];

if (!is_null($completionview)) {
Expand All @@ -278,13 +338,16 @@ public function test_get_details(int $completion, ?int $completionview, ?int $co
if (!is_null($completiongrade)) {
$options['completionusegrade'] = true;
}
if (!is_null($completionpassgrade)) {
$options['completionpassgrade'] = true;
}

$cmcompletion = $this->setup_data($completion, $options, $getdatareturn);
$this->assertEquals($expecteddetails, $cmcompletion->get_details());
}

/**
* Data provider for test_get_details().
* Data provider for test_get_details_custom_order().
* @return array[]
*/
public function get_details_custom_order_provider() {
Expand Down
87 changes: 49 additions & 38 deletions lib/completionlib.php
Expand Up @@ -697,14 +697,6 @@ public function internal_get_state($cm, $userid, $current) {
}

$newstate = COMPLETION_COMPLETE;
$completionstate = [];
if ($cm->completionview == COMPLETION_VIEW_REQUIRED) {
$newstate = ($current->viewed == COMPLETION_VIEWED ? COMPLETION_COMPLETE : COMPLETION_INCOMPLETE);
$completionstate = [
'viewed' => $newstate
];
}

if ($cm instanceof stdClass) {
// Modname hopefully is provided in $cm but just in case it isn't, let's grab it.
if (!isset($cm->modname)) {
Expand All @@ -717,35 +709,14 @@ public function internal_get_state($cm, $userid, $current) {
}
// Make sure we're using a cm_info object.
$cminfo = cm_info::create($cm, $userid);

// Check grade
if (!is_null($cminfo->completiongradeitemnumber)) {
$newstate = $this->get_grade_completion($cminfo, $userid);
$completionstate['usegrade'] = $newstate;
if ($cm->completionpassgrade) {
// If we are asking to use pass grade completion but haven't set it properly,
// then default to COMPLETION_COMPLETE_PASS.
if ($newstate == COMPLETION_COMPLETE) {
$newstate = COMPLETION_COMPLETE_PASS;
}

// The criteria is to mark an activity as complete if a passing grade has been achieved.
// COMPLETION_COMPLETE_FAIL still marks the activity as completed which is incorrect.
// Rectify this.
if ($newstate == COMPLETION_COMPLETE_FAIL) {
$newstate = COMPLETION_INCOMPLETE;
}

$completionstate['passgrade'] = $newstate;
}
}
$completionstate = $this->get_core_completion_state($cminfo, $userid);

if (plugin_supports('mod', $cminfo->modname, FEATURE_COMPLETION_HAS_RULES)) {
$response = true;
$cmcompletionclass = activity_custom_completion::get_cm_completion_class($cminfo->modname);
if ($cmcompletionclass) {
/** @var activity_custom_completion $cmcompletion */
$cmcompletion = new $cmcompletionclass($cminfo, $userid);
$cmcompletion = new $cmcompletionclass($cminfo, $userid, $completionstate);
$response = $cmcompletion->get_overall_completion_state() != COMPLETION_INCOMPLETE;
} else {
// Fallback to the get_completion_state callback.
Expand Down Expand Up @@ -1167,6 +1138,51 @@ public function get_data($cm, $wholecourse = false, $userid = 0, $modinfo = null
return (object)$cacheddata[$cminfo->id];
}

/**
* Get the latest completion state for each criteria used in the module
*
* @param cm_info $cm The corresponding module's information
* @param int $userid The id for the user we are calculating core completion state
* @return array $data The individualised core completion state used in the module.
* Consists of the following keys completiongrade, passgrade, viewed
*/
public function get_core_completion_state(cm_info $cm, int $userid): array {
global $DB;
$data = [];
// Include in the completion info the grade completion, if necessary.
if (!is_null($cm->completiongradeitemnumber)) {
$newstate = $this->get_grade_completion($cm, $userid);
$data['completiongrade'] = $newstate;

if ($cm->completionpassgrade) {
// If we are asking to use pass grade completion but haven't set it properly,
// then default to COMPLETION_COMPLETE_PASS.
if ($newstate == COMPLETION_COMPLETE) {
$newstate = COMPLETION_COMPLETE_PASS;
}

// The activity is using 'passing grade' criteria therefore fail indication should be on this criteria.
// The user has received a (failing) grade so 'completiongrade' should properly indicate this.
if ($newstate == COMPLETION_COMPLETE_FAIL) {
$data['completiongrade'] = COMPLETION_COMPLETE;
}

$data['passgrade'] = $newstate;
}
}

// If view is required, try and fetch from the db. In some cases, cache can be invalid.
if ($cm->completionview == COMPLETION_VIEW_REQUIRED) {
$data['viewed'] = COMPLETION_INCOMPLETE;
$record = $DB->get_record('course_modules_completion', array('coursemoduleid' => $cm->id, 'userid' => $userid));
if ($record) {
$data['viewed'] = ($record->viewed == COMPLETION_VIEWED ? COMPLETION_COMPLETE : COMPLETION_INCOMPLETE);
}
}

return $data;
}

/**
* Adds the user's custom completion data on the given course module.
*
Expand All @@ -1175,12 +1191,7 @@ public function get_data($cm, $wholecourse = false, $userid = 0, $modinfo = null
* @return array The additional completion data.
*/
protected function get_other_cm_completion_data(cm_info $cm, int $userid): array {
$data = [];

// Include in the completion info the grade completion, if necessary.
if (!is_null($cm->completiongradeitemnumber)) {
$data['completiongrade'] = $this->get_grade_completion($cm, $userid);
}
$data = $this->get_core_completion_state($cm, $userid);

// Custom activity module completion data.

Expand All @@ -1200,7 +1211,7 @@ protected function get_other_cm_completion_data(cm_info $cm, int $userid): array
}

/** @var activity_custom_completion $customcmcompletion */
$customcmcompletion = new $cmcompletionclass($cm, $userid);
$customcmcompletion = new $cmcompletionclass($cm, $userid, $data);
foreach ($customdata['customcompletionrules'] as $rule => $enabled) {
if (!$enabled) {
// Skip inactive completion rules.
Expand Down
1 change: 1 addition & 0 deletions mod/assign/classes/completion/custom_completion.php
Expand Up @@ -89,6 +89,7 @@ public function get_sort_order(): array {
'completionview',
'completionsubmit',
'completionusegrade',
'completionpassgrade',
];
}
}
1 change: 1 addition & 0 deletions mod/data/classes/completion/custom_completion.php
Expand Up @@ -80,6 +80,7 @@ public function get_sort_order(): array {
'completionview',
'completionentries',
'completionusegrade',
'completionpassgrade',
];
}
}
1 change: 1 addition & 0 deletions mod/forum/classes/completion/custom_completion.php
Expand Up @@ -112,6 +112,7 @@ public function get_sort_order(): array {
'completionreplies',
'completionposts',
'completionusegrade',
'completionpassgrade',
];
}
}
1 change: 1 addition & 0 deletions mod/glossary/classes/completion/custom_completion.php
Expand Up @@ -84,6 +84,7 @@ public function get_sort_order(): array {
'completionview',
'completionentries',
'completionusegrade',
'completionpassgrade',
];
}
}
1 change: 1 addition & 0 deletions mod/lesson/classes/completion/custom_completion.php
Expand Up @@ -103,6 +103,7 @@ public function get_sort_order(): array {
'completiontimespent',
'completionendreached',
'completionusegrade',
'completionpassgrade',
];
}
}

0 comments on commit 2c7893c

Please sign in to comment.