Currently the gradebook user interface accesses the gradebook data using an internal API of classes:
cvs:/moodle/lib/grade
This is not really intended for use by modules.
We can easily come up with some simple functions to act as a layer over these to perform common queries.
My question is: what are these common queries? What sort of answers do you want to extract easily from the gradebook?
G'day Martin!
As for me, you know that the certificate gets grade data for both printing and for locking, so I would LOVE to have some simple functions for this. Currently we have functions that:
get the graded activities in a course (used for options in mod_form.php)
get the actual user grade for any given activity
I would also like to see a transcripts page (similar to my moodle) that shows completed (unenrolled) courses and lists the activity grades -- these functions would make that easy.
Thanks
As for me, you know that the certificate gets grade data for both printing and for locking, so I would LOVE to have some simple functions for this. Currently we have functions that:
get the graded activities in a course (used for options in mod_form.php)
get the actual user grade for any given activity
I would also like to see a transcripts page (similar to my moodle) that shows completed (unenrolled) courses and lists the activity grades -- these functions would make that easy.
Thanks
hello,
at present we have grade related public API only for modules. This can be found in lib/gradelib.php, you can:
* modules can report updated raw grades
* you can get a list of outcomes attached to activities and update them
* you can get a list of final grades for activities
* you can find out if activity grading is locked
Most of the interesting information can be obtained through the grade_item class that is defined in lib/grade/grade_item.php - interfaces of grade classes are not considered public.
It should be easy to make some more public functions, the only problem might be performance - we can not pass thousands of grades around or fetch one by one
at present we have grade related public API only for modules. This can be found in lib/gradelib.php, you can:
* modules can report updated raw grades
* you can get a list of outcomes attached to activities and update them
* you can get a list of final grades for activities
* you can find out if activity grading is locked
Most of the interesting information can be obtained through the grade_item class that is defined in lib/grade/grade_item.php - interfaces of grade classes are not considered public.
It should be easy to make some more public functions, the only problem might be performance - we can not pass thousands of grades around or fetch one by one
I've put in some proposed functions for the gradebook API here:
http://docs.moodle.org/en/Development:Grades#Core_API_functions
Does that look OK? Note that some calls will be a two-step process: one to get the grade_item (ie column) for an activity, then a second to get information (like grades) using that grade_item. This is because there are other sorts of grade items apart from those attached to activities, plus you'll often want to be able to get all grade_items in bulk and step through them.
Please give feedback now, because these will be locked in stone after 1.9 release!
http://docs.moodle.org/en/Development:Grades#Core_API_functions
Does that look OK? Note that some calls will be a two-step process: one to get the grade_item (ie column) for an activity, then a second to get information (like grades) using that grade_item. This is because there are other sorts of grade items apart from those attached to activities, plus you'll often want to be able to get all grade_items in bulk and step through them.
Please give feedback now, because these will be locked in stone after 1.9 release!
So you get the grade_items you want, and then pass one of the grade_items back to a function to get specific information. Is that correct?
It looks like grade_items is an object. Why not make it a class with class functions instead? That way, we wouldn't have to pass it back to the functions.
mike
It looks like grade_items is an object. Why not make it a class with class functions instead? That way, we wouldn't have to pass it back to the functions.
mike
I'm a little confused about getting grade_items as objects. I used to use an activity's _grades function to return both the grademax (used to be maxgrade) and the user grade. Now will I need to use 3 functions? One to get the graded activities, one to get the grademax for each graded activity and one to get the user grade for each activity? Would it work to be able to get grade items using grade_get_grade_activities()?
I'll do some testing as soon as these get added to cvs.
Thanks Martin.
I'll do some testing as soon as these get added to cvs.
Thanks Martin.
The grade_item contains all the info about that grade column. Maxgrade, mingrade, pass grade etc etc etc (there's a lot of stuff).
You cuold use grade_get_grade_items() just to get all these for a course in one step.
I've just asked Nicolas to implement all these now. MDL-9506
You cuold use grade_get_grade_items() just to get all these for a course in one step.
I've just asked Nicolas to implement all these now. MDL-9506
Mike, the pragmatic answer to your question is that grade_items are already objects internal to the gradebook. They already have lots of methods that are only really meant to be used within the gradebook.
So making the external API consist only of functions keeps things separate.
So making the external API consist only of functions keeps things separate.
Hello Martin !
I see with interest that some function can be used at site level ( when course id isn't provided). But this logical is not really complete because it doesn't exist site level grades category, or I missed something...
Do you think that this functionnality would to be add ?
I see with interest that some function can be used at site level ( when course id isn't provided). But this logical is not really complete because it doesn't exist site level grades category, or I missed something...
Do you think that this functionnality would to be add ?
I need some help with the new API. I can't get items for a given activity. I need to get the grademax and then I need to get the itemid to use for grade_get_user_grade
I get this error: Notice: Undefined property: stdClass::$courseid in D:\moodle\moodle\moodle\lib\gradelib.php on line 465
with this code:
$cm = get_record('course_modules', 'id', $moduleid);
$items = grade_get_grade_items_for_activity($cm);
I've tried everything I can think of to get that courseid in there ($course is a variable in my function). Any help would be really appreciated.
I get this error: Notice: Undefined property: stdClass::$courseid in D:\moodle\moodle\moodle\lib\gradelib.php on line 465
with this code:
$cm = get_record('course_modules', 'id', $moduleid);
$items = grade_get_grade_items_for_activity($cm);
I've tried everything I can think of to get that courseid in there ($course is a variable in my function). Any help would be really appreciated.
Chardelle - This is reminiscent of a similar error I was seeing when working on the gradebookplusv2 patch. Do you have any 3rd party modules installed? Peace - Anthony
Maybe I should be using $items = grade_get_grade_items($course->id, $module->name); instead of grade_get_grade_items_for_activity
But I this gives an array, right? So, I'm still not quite sure what I need.
But I this gives an array, right? So, I'm still not quite sure what I need.
CB,
Yes. But so does grade_get_grade_items_for_activity (EDIT: unless there is only one, or none). Either way you have to give it the course id, if you want to restrict it to one course; in one case, as the first argument; in the other, as a property of the only argument ($cm->courseid). So what's the advantage of using one function over the other?
EDIT: Looking at the code at the beginning of grade_get_grade_items_for_activity, you are supposed to give it a course module object as an argument. If you had done so, and it was missing the courseid, you would have gotten a different error msg.:
The coursemodule object you gave to grade_exists() isn't set up correctly. Either instance ($cm->instance) or courseid ($cm->courseid) field isn't set.
The error msg. you did get says that you gave it a different class of object instead. Your post indicates it came from get_record, which at best returns a fieldset object. That's the problem.
RLE
Yes. But so does grade_get_grade_items_for_activity (EDIT: unless there is only one, or none). Either way you have to give it the course id, if you want to restrict it to one course; in one case, as the first argument; in the other, as a property of the only argument ($cm->courseid). So what's the advantage of using one function over the other?
EDIT: Looking at the code at the beginning of grade_get_grade_items_for_activity, you are supposed to give it a course module object as an argument. If you had done so, and it was missing the courseid, you would have gotten a different error msg.:
The coursemodule object you gave to grade_exists() isn't set up correctly. Either instance ($cm->instance) or courseid ($cm->courseid) field isn't set.
The error msg. you did get says that you gave it a different class of object instead. Your post indicates it came from get_record, which at best returns a fieldset object. That's the problem.
RLE
Here's a little secret. I'm not a coder, not a PHP programmer, I don't know a fieldset object from my a**. When David Cannon wasn't able to update the certificate from 1.6 on, I took over. It needed backup/restore. Ok, go look at the journal mod and see how its done. Wouldn't it be nice to save the certificates in moddata? Hmmm, go look at the assignment mod and see how it saves the files. Now we need to update for roles, update for mod_form, add some functions and on and on. Go look at other code, hack away for hours on end, then somehow manage to get it to work. That's how I've volunteered my time to maintain and develop the certificate.
There are 3 functions in the certificate that rely on the deprecated _grades functions. Now it needs updated to the new gradelib API. I tried to get it to work, but I can't. If anyone would like to volunteer (how about someone using the certificate?), that would be great. Then, I can also update the activity locking code for 1.9 too -- it relies on similar deprecated functions.
/************************************************************************
* Search through all the modules, pulling out grade data *
************************************************************************/
function certificate_get_mod_grades() {
global $course, $CFG;
/// Collect modules data
get_all_mods($course->id, $mods, $modnames, $modnamesplural, $modnamesused);
$printgrade = array();
$sections = get_all_sections($course->id); // Sort everything the same as the course
for ($i=0; $i<=$course->numsections; $i++) {
// should always be true
if (isset($sections[$i])) {
$section = $sections[$i];
if ($section->sequence) {
switch ($course->format) {
case "topics":
$sectionlabel = get_string("topic");
break;
case "weeks":
$sectionlabel = get_string("week");
break;
default:
$sectionlabel = get_string("section");
}
$sectionmods = explode(",", $section->sequence);
foreach ($sectionmods as $sectionmod) {
if (empty($mods[$sectionmod])) {
continue;
}
$mod = $mods[$sectionmod];
// no labels
if ( $mod->modname != "label") {
$instance = get_record("$mod->modname", "id", "$mod->instance");
$libfile = "$CFG->dirroot/mod/$mod->modname/lib.php";
if (file_exists($libfile)) {
require_once($libfile);
$gradefunction = $mod->modname."_grades";
// Modules with grade function (excluding forums)
if (function_exists($gradefunction) and $mod->modname != "forum") {
// Modules with grading set
if ($modgrades = $gradefunction($mod->instance) and !empty($modgrades->maxgrade)) {
$printgrade[$mod->id] = $sectionlabel.' '.$section->section.' : '.$instance->name;
}
}
else { //Modules without a grade set but with a grade function
}
} // libfile
} // no labels
} //close foreach
} // if section
} // isset section
}
if(isset($printgrade)) {
$gradeoptions['0'] = get_string('no');
$gradeoptions['1'] = get_string('coursegradeoption', 'certificate');
foreach($printgrade as $key => $value) {
$gradeoptions[$key] = $value;
}
} else { $gradeoptions['0'] = get_string('nogrades', 'certificate'); }
return ($gradeoptions);
}
/************************************************************************
* Prepare mod grade for printing *
************************************************************************/
function certificate_mod_grade($course, $moduleid) {
global $USER, $CFG;
$cm = get_record("course_modules", "id", $moduleid);
$module = get_record("modules", "id", $cm->module);
$libfile = $CFG->dirroot."/mod/".$module->name."/lib.php";
if (file_exists($libfile)) {
require_once($libfile);
$gradefunction = $module->name."_grades";
if (function_exists($gradefunction)) {
if ($modgrades = $gradefunction($cm->instance)) {
$modinfo->name = utf8_decode(get_field($module->name, 'name', 'id', $cm->instance));
$modinfo->percentage = round(($modgrades->grades[$USER->id]*100/$modgrades->maxgrade),2);
$modinfo->points = $modgrades->grades[$USER->id];
return $modinfo;
}
}
}
return false;
}
/************************************************************************
* Search through all the modules, pulling out grade data *
* and prepare to print the course grade. *
************************************************************************/
function certificate_get_course_grade($id){
global $course, $CFG, $USER;
$course = get_record("course", "id", $id);
$strgrades = get_string("grades");
$strgrade = get_string("grade");
$strmax = get_string("maximumshort");
$stractivityreport = get_string("activityreport");
/// Get a list of all students
$columnhtml = array(); // Accumulate column html in this array.
$grades = array(); // Collect all grades in this array
$maxgrades = array(); // Collect all max grades in this array
$totalgrade = 0;
$totalmaxgrade = .000001;
/// Collect modules data
$test=get_all_mods($course->id, $mods, $modnames, $modnamesplural, $modnamesused);
/// Search through all the modules, pulling out grade data
$sections = get_all_sections($course->id); // Sort everything the same as the course
for ($i=0; $i<=$course->numsections; $i++) {
if (isset($sections[$i])) { // should always be true
$section = $sections[$i];
if (!empty($section->sequence)) {
$sectionmods = explode(",", $section->sequence);
foreach ($sectionmods as $sectionmod) {
if (empty($mods[$sectionmod])) {
continue;
}
$mod = $mods[$sectionmod];
$context = get_context_instance(CONTEXT_MODULE, $mod->id);
if ($mod->visible || has_capability('moodle/course:viewhiddenactivities', $context)) {
$instance = get_record("$mod->modname", "id", "$mod->instance");
$libfile = "$CFG->dirroot/mod/$mod->modname/lib.php";
if (file_exists($libfile)) {
require_once($libfile);
$gradefunction = $mod->modname."_grades";
if (function_exists($gradefunction)) { // Skip modules without grade function
if ($modgrades = $gradefunction($mod->instance)) {
if (empty($modgrades->grades[$USER->id])) {
$grades[] = "";
} else {
$grades[] = $modgrades->grades[$USER->id];
$totalgrade += (float)$modgrades->grades[$USER->id];
}
if (empty($modgrades->maxgrade) || empty($modgrades)) {
$maxgrades[] = "";
} else {
$maxgrades[] = $modgrades->maxgrade;
$totalmaxgrade += $modgrades->maxgrade;
}
}
}
}
}
}
}
}
}
$coursegrade->percentage = round(($totalgrade*100/$totalmaxgrade),2);
$coursegrade->points = $totalgrade;
return $coursegrade;
}
There are 3 functions in the certificate that rely on the deprecated _grades functions. Now it needs updated to the new gradelib API. I tried to get it to work, but I can't. If anyone would like to volunteer (how about someone using the certificate?), that would be great. Then, I can also update the activity locking code for 1.9 too -- it relies on similar deprecated functions.
/************************************************************************
* Search through all the modules, pulling out grade data *
************************************************************************/
function certificate_get_mod_grades() {
global $course, $CFG;
/// Collect modules data
get_all_mods($course->id, $mods, $modnames, $modnamesplural, $modnamesused);
$printgrade = array();
$sections = get_all_sections($course->id); // Sort everything the same as the course
for ($i=0; $i<=$course->numsections; $i++) {
// should always be true
if (isset($sections[$i])) {
$section = $sections[$i];
if ($section->sequence) {
switch ($course->format) {
case "topics":
$sectionlabel = get_string("topic");
break;
case "weeks":
$sectionlabel = get_string("week");
break;
default:
$sectionlabel = get_string("section");
}
$sectionmods = explode(",", $section->sequence);
foreach ($sectionmods as $sectionmod) {
if (empty($mods[$sectionmod])) {
continue;
}
$mod = $mods[$sectionmod];
// no labels
if ( $mod->modname != "label") {
$instance = get_record("$mod->modname", "id", "$mod->instance");
$libfile = "$CFG->dirroot/mod/$mod->modname/lib.php";
if (file_exists($libfile)) {
require_once($libfile);
$gradefunction = $mod->modname."_grades";
// Modules with grade function (excluding forums)
if (function_exists($gradefunction) and $mod->modname != "forum") {
// Modules with grading set
if ($modgrades = $gradefunction($mod->instance) and !empty($modgrades->maxgrade)) {
$printgrade[$mod->id] = $sectionlabel.' '.$section->section.' : '.$instance->name;
}
}
else { //Modules without a grade set but with a grade function
}
} // libfile
} // no labels
} //close foreach
} // if section
} // isset section
}
if(isset($printgrade)) {
$gradeoptions['0'] = get_string('no');
$gradeoptions['1'] = get_string('coursegradeoption', 'certificate');
foreach($printgrade as $key => $value) {
$gradeoptions[$key] = $value;
}
} else { $gradeoptions['0'] = get_string('nogrades', 'certificate'); }
return ($gradeoptions);
}
/************************************************************************
* Prepare mod grade for printing *
************************************************************************/
function certificate_mod_grade($course, $moduleid) {
global $USER, $CFG;
$cm = get_record("course_modules", "id", $moduleid);
$module = get_record("modules", "id", $cm->module);
$libfile = $CFG->dirroot."/mod/".$module->name."/lib.php";
if (file_exists($libfile)) {
require_once($libfile);
$gradefunction = $module->name."_grades";
if (function_exists($gradefunction)) {
if ($modgrades = $gradefunction($cm->instance)) {
$modinfo->name = utf8_decode(get_field($module->name, 'name', 'id', $cm->instance));
$modinfo->percentage = round(($modgrades->grades[$USER->id]*100/$modgrades->maxgrade),2);
$modinfo->points = $modgrades->grades[$USER->id];
return $modinfo;
}
}
}
return false;
}
/************************************************************************
* Search through all the modules, pulling out grade data *
* and prepare to print the course grade. *
************************************************************************/
function certificate_get_course_grade($id){
global $course, $CFG, $USER;
$course = get_record("course", "id", $id);
$strgrades = get_string("grades");
$strgrade = get_string("grade");
$strmax = get_string("maximumshort");
$stractivityreport = get_string("activityreport");
/// Get a list of all students
$columnhtml = array(); // Accumulate column html in this array.
$grades = array(); // Collect all grades in this array
$maxgrades = array(); // Collect all max grades in this array
$totalgrade = 0;
$totalmaxgrade = .000001;
/// Collect modules data
$test=get_all_mods($course->id, $mods, $modnames, $modnamesplural, $modnamesused);
/// Search through all the modules, pulling out grade data
$sections = get_all_sections($course->id); // Sort everything the same as the course
for ($i=0; $i<=$course->numsections; $i++) {
if (isset($sections[$i])) { // should always be true
$section = $sections[$i];
if (!empty($section->sequence)) {
$sectionmods = explode(",", $section->sequence);
foreach ($sectionmods as $sectionmod) {
if (empty($mods[$sectionmod])) {
continue;
}
$mod = $mods[$sectionmod];
$context = get_context_instance(CONTEXT_MODULE, $mod->id);
if ($mod->visible || has_capability('moodle/course:viewhiddenactivities', $context)) {
$instance = get_record("$mod->modname", "id", "$mod->instance");
$libfile = "$CFG->dirroot/mod/$mod->modname/lib.php";
if (file_exists($libfile)) {
require_once($libfile);
$gradefunction = $mod->modname."_grades";
if (function_exists($gradefunction)) { // Skip modules without grade function
if ($modgrades = $gradefunction($mod->instance)) {
if (empty($modgrades->grades[$USER->id])) {
$grades[] = "";
} else {
$grades[] = $modgrades->grades[$USER->id];
$totalgrade += (float)$modgrades->grades[$USER->id];
}
if (empty($modgrades->maxgrade) || empty($modgrades)) {
$maxgrades[] = "";
} else {
$maxgrades[] = $modgrades->maxgrade;
$totalmaxgrade += $modgrades->maxgrade;
}
}
}
}
}
}
}
}
}
$coursegrade->percentage = round(($totalgrade*100/$totalmaxgrade),2);
$coursegrade->points = $totalgrade;
return $coursegrade;
}
I don´t know why but wheb I try to add conditional access via Activity Lock Block, I see always this message:
The coursemodule object you gave to grade_exists() isn't set up correctly. Either instance () or courseid (4) field isn't set.
I don´t know how to solve
I´m using moodle 1.9
The coursemodule object you gave to grade_exists() isn't set up correctly. Either instance () or courseid (4) field isn't set.
I don´t know how to solve
I´m using moodle 1.9