mirror of
https://github.com/moodle/moodle.git
synced 2025-08-05 08:56:36 +02:00
MDL-70815 core_completion: completion_info::get_grade_completion()
Move the current logic for determining the completion status for the "Student must receive grade" completion rule to a function so it cann be reused. Unit test included.
This commit is contained in:
parent
baa0001037
commit
31fcbfc2e2
2 changed files with 112 additions and 32 deletions
|
@ -643,7 +643,7 @@ class completion_info {
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function internal_get_state($cm, $userid, $current) {
|
public function internal_get_state($cm, $userid, $current) {
|
||||||
global $USER, $DB, $CFG;
|
global $USER, $DB;
|
||||||
|
|
||||||
// Get user ID
|
// Get user ID
|
||||||
if (!$userid) {
|
if (!$userid) {
|
||||||
|
@ -657,49 +657,37 @@ class completion_info {
|
||||||
return COMPLETION_INCOMPLETE;
|
return COMPLETION_INCOMPLETE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Modname hopefully is provided in $cm but just in case it isn't, let's grab it
|
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)) {
|
if (!isset($cm->modname)) {
|
||||||
$cm->modname = $DB->get_field('modules', 'name', array('id' => $cm->module));
|
$cm->modname = $DB->get_field('modules', 'name', array('id' => $cm->module));
|
||||||
}
|
}
|
||||||
|
// Some functions call this method and pass $cm as an object with ID only. Make sure course is set as well.
|
||||||
|
if (!isset($cm->course)) {
|
||||||
|
$cm->course = $this->course_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Make sure we're using a cm_info object.
|
||||||
|
$cminfo = cm_info::create($cm, $userid);
|
||||||
|
|
||||||
$newstate = COMPLETION_COMPLETE;
|
$newstate = COMPLETION_COMPLETE;
|
||||||
|
|
||||||
// Check grade
|
// Check grade
|
||||||
if (!is_null($cm->completiongradeitemnumber)) {
|
if (!is_null($cminfo->completiongradeitemnumber)) {
|
||||||
require_once($CFG->libdir.'/gradelib.php');
|
$newstate = $this->get_grade_completion($cminfo, $userid);
|
||||||
$item = grade_item::fetch(array('courseid'=>$cm->course, 'itemtype'=>'mod',
|
|
||||||
'itemmodule'=>$cm->modname, 'iteminstance'=>$cm->instance,
|
|
||||||
'itemnumber'=>$cm->completiongradeitemnumber));
|
|
||||||
if ($item) {
|
|
||||||
// Fetch 'grades' (will be one or none)
|
|
||||||
$grades = grade_grade::fetch_users_grades($item, array($userid), false);
|
|
||||||
if (empty($grades)) {
|
|
||||||
// No grade for user
|
|
||||||
return COMPLETION_INCOMPLETE;
|
|
||||||
}
|
|
||||||
if (count($grades) > 1) {
|
|
||||||
$this->internal_systemerror("Unexpected result: multiple grades for
|
|
||||||
item '{$item->id}', user '{$userid}'");
|
|
||||||
}
|
|
||||||
$newstate = self::internal_get_grade_state($item, reset($grades));
|
|
||||||
if ($newstate == COMPLETION_INCOMPLETE) {
|
if ($newstate == COMPLETION_INCOMPLETE) {
|
||||||
return COMPLETION_INCOMPLETE;
|
return COMPLETION_INCOMPLETE;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
|
||||||
$this->internal_systemerror("Cannot find grade item for '{$cm->modname}'
|
|
||||||
cm '{$cm->id}' matching number '{$cm->completiongradeitemnumber}'");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (plugin_supports('mod', $cm->modname, FEATURE_COMPLETION_HAS_RULES)) {
|
if (plugin_supports('mod', $cminfo->modname, FEATURE_COMPLETION_HAS_RULES)) {
|
||||||
$function = $cm->modname.'_get_completion_state';
|
$function = $cminfo->modname . '_get_completion_state';
|
||||||
if (!function_exists($function)) {
|
if (!function_exists($function)) {
|
||||||
$this->internal_systemerror("Module {$cm->modname} claims to support
|
$this->internal_systemerror("Module {$cminfo->modname} claims to support
|
||||||
FEATURE_COMPLETION_HAS_RULES but does not have required
|
FEATURE_COMPLETION_HAS_RULES but does not have required
|
||||||
{$cm->modname}_get_completion_state function");
|
{$cm->modname}_get_completion_state function");
|
||||||
}
|
}
|
||||||
if (!$function($this->course, $cm, $userid, COMPLETION_AND)) {
|
if (!$function($this->course, $cminfo, $userid, COMPLETION_AND)) {
|
||||||
return COMPLETION_INCOMPLETE;
|
return COMPLETION_INCOMPLETE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -708,6 +696,44 @@ class completion_info {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches the completion state for an activity completion's require grade completion requirement.
|
||||||
|
*
|
||||||
|
* @param cm_info $cm The course module information.
|
||||||
|
* @param int $userid The user ID.
|
||||||
|
* @return int The completion state.
|
||||||
|
*/
|
||||||
|
public function get_grade_completion(cm_info $cm, int $userid): int {
|
||||||
|
global $CFG;
|
||||||
|
|
||||||
|
require_once($CFG->libdir . '/gradelib.php');
|
||||||
|
$item = grade_item::fetch([
|
||||||
|
'courseid' => $cm->course,
|
||||||
|
'itemtype' => 'mod',
|
||||||
|
'itemmodule' => $cm->modname,
|
||||||
|
'iteminstance' => $cm->instance,
|
||||||
|
'itemnumber' => $cm->completiongradeitemnumber
|
||||||
|
]);
|
||||||
|
if ($item) {
|
||||||
|
// Fetch 'grades' (will be one or none).
|
||||||
|
$grades = grade_grade::fetch_users_grades($item, [$userid], false);
|
||||||
|
if (empty($grades)) {
|
||||||
|
// No grade for user.
|
||||||
|
return COMPLETION_INCOMPLETE;
|
||||||
|
}
|
||||||
|
if (count($grades) > 1) {
|
||||||
|
$this->internal_systemerror("Unexpected result: multiple grades for
|
||||||
|
item '{$item->id}', user '{$userid}'");
|
||||||
|
}
|
||||||
|
return self::internal_get_grade_state($item, reset($grades));
|
||||||
|
} else {
|
||||||
|
$this->internal_systemerror("Cannot find grade item for '{$cm->modname}'
|
||||||
|
cm '{$cm->id}' matching number '{$cm->completiongradeitemnumber}'");
|
||||||
|
}
|
||||||
|
|
||||||
|
return COMPLETION_INCOMPLETE;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Marks a module as viewed.
|
* Marks a module as viewed.
|
||||||
*
|
*
|
||||||
|
|
|
@ -1143,6 +1143,60 @@ class core_completionlib_testcase extends advanced_testcase {
|
||||||
$this->assertTrue(completion_can_view_data($student->id, $this->course->id));
|
$this->assertTrue(completion_can_view_data($student->id, $this->course->id));
|
||||||
$this->assertFalse(completion_can_view_data($this->user->id, $this->course->id));
|
$this->assertFalse(completion_can_view_data($this->user->id, $this->course->id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data provider for test_get_grade_completion().
|
||||||
|
*
|
||||||
|
* @return array[]
|
||||||
|
*/
|
||||||
|
public function get_grade_completion_provider() {
|
||||||
|
return [
|
||||||
|
'Grade not required' => [false, false, null, moodle_exception::class, null],
|
||||||
|
'Grade required, but has no grade yet' => [true, false, null, null, COMPLETION_INCOMPLETE],
|
||||||
|
'Grade required, grade received' => [true, true, null, null, COMPLETION_COMPLETE],
|
||||||
|
'Grade required, passing grade received' => [true, true, 70, null, COMPLETION_COMPLETE_PASS],
|
||||||
|
'Grade required, failing grade received' => [true, true, 80, null, COMPLETION_COMPLETE_FAIL],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test for \completion_info::get_grade_completion().
|
||||||
|
*
|
||||||
|
* @dataProvider get_grade_completion_provider
|
||||||
|
* @param bool $completionusegrade Whether the test activity has grade completion requirement.
|
||||||
|
* @param bool $hasgrade Whether to set grade for the user in this activity.
|
||||||
|
* @param int|null $passinggrade Passing grade to set for the test activity.
|
||||||
|
* @param string|null $expectedexception Expected exception.
|
||||||
|
* @param int|null $expectedresult The expected completion status.
|
||||||
|
*/
|
||||||
|
public function test_get_grade_completion(bool $completionusegrade, bool $hasgrade, ?int $passinggrade, ?string $expectedexception,
|
||||||
|
?int $expectedresult) {
|
||||||
|
$this->setup_data();
|
||||||
|
|
||||||
|
/** @var \mod_assign_generator $assigngenerator */
|
||||||
|
$assigngenerator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
|
||||||
|
$assign = $assigngenerator->create_instance([
|
||||||
|
'course' => $this->course->id,
|
||||||
|
'completion' => COMPLETION_ENABLED,
|
||||||
|
'completionusegrade' => $completionusegrade,
|
||||||
|
'gradepass' => $passinggrade,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$cm = cm_info::create(get_coursemodule_from_instance('assign', $assign->id));
|
||||||
|
if ($completionusegrade && $hasgrade) {
|
||||||
|
$assigninstance = new assign($cm->context, $cm, $this->course);
|
||||||
|
$grade = $assigninstance->get_user_grade($this->user->id, true);
|
||||||
|
$grade->grade = 75;
|
||||||
|
$assigninstance->update_grade($grade);
|
||||||
|
}
|
||||||
|
|
||||||
|
$completioninfo = new completion_info($this->course);
|
||||||
|
if ($expectedexception) {
|
||||||
|
$this->expectException($expectedexception);
|
||||||
|
}
|
||||||
|
$gradecompletion = $completioninfo->get_grade_completion($cm, $this->user->id);
|
||||||
|
$this->assertEquals($expectedresult, $gradecompletion);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class core_completionlib_fake_recordset implements Iterator {
|
class core_completionlib_fake_recordset implements Iterator {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue