// enable outcomes checkbox
$temp->add(new admin_setting_configcheckbox('enableoutcomes', get_string('enableoutcomes', 'grades'), get_string('configenableoutcomes', 'grades'), 0, PARAM_INT));
-// enable publishing in exports/imports
-$temp->add(new admin_setting_configcheckbox('gradepublishing', get_string('gradepublishing', 'grades'), get_string('configgradepublishing', 'grades'), 0, PARAM_INT));
$temp->add(new admin_setting_configselect('grade_aggregationposition', get_string('aggregationposition', 'grades'),
get_string('configaggregationposition', 'grades'), GRADE_REPORT_AGGREGATION_POSITION_LAST,
'4' => '4',
'5' => '5')));
+$temp->add(new admin_setting_configcheckbox('grade_hiddenasdate', get_string('hiddenasdate', 'grades'), get_string('confighiddenasdate', 'grades'), 0, PARAM_INT));
+
+// enable publishing in exports/imports
+$temp->add(new admin_setting_configcheckbox('gradepublishing', get_string('gradepublishing', 'grades'), get_string('configgradepublishing', 'grades'), 0, PARAM_INT));
+
$temp->add(new admin_setting_configselect('grade_export_displaytype', get_string('gradeexportdisplaytype', 'grades'),
get_string('configgradeexportdisplaytype', 'grades'), GRADE_DISPLAY_TYPE_REAL,
array(GRADE_DISPLAY_TYPE_REAL => get_string('real', 'grades'),
'2' => '2',
'3' => '3',
'4' => '4',
- '5' => '5')));
-
+ '5' => '5')));
+
$temp->add(new admin_setting_special_gradeexport());
$ADMIN->add('grades', $temp);
-/// Scales and outcomes
-
-$scales = new admin_externalpage('scales', get_string('scales'), $CFG->wwwroot.'/grade/edit/scale/index.php', 'moodle/grade:manage');
-$ADMIN->add('grades', $scales);
-$outcomes = new admin_externalpage('outcomes', get_string('outcomes', 'grades'), $CFG->wwwroot.'/grade/edit/outcome/index.php', 'moodle/grade:manage');
-$ADMIN->add('grades', $outcomes);
-$letters = new admin_externalpage('letters', get_string('letters', 'grades'), $CFG->wwwroot.'/grade/edit/letter/edit.php', 'moodle/grade:manageletters');
-$ADMIN->add('grades', $letters);
-
/// Grade category settings
$temp = new admin_settingpage('gradecategorysettings', get_string('gradecategorysettings', 'grades'));
$ADMIN->add('grades', $temp);
+/// Scales and outcomes
+
+$scales = new admin_externalpage('scales', get_string('scales'), $CFG->wwwroot.'/grade/edit/scale/index.php', 'moodle/grade:manage');
+$ADMIN->add('grades', $scales);
+$outcomes = new admin_externalpage('outcomes', get_string('outcomes', 'grades'), $CFG->wwwroot.'/grade/edit/outcome/index.php', 'moodle/grade:manage');
+$ADMIN->add('grades', $outcomes);
+$letters = new admin_externalpage('letters', get_string('letters', 'grades'), $CFG->wwwroot.'/grade/edit/letter/edit.php', 'moodle/grade:manageletters');
+$ADMIN->add('grades', $letters);
+
// The plugins must implement a settings.php file that adds their admin settings to the $settings object
// Reports
}
}
- $icon = '<img src="'.$CFG->wwwroot.'/pix/spacer.gif" class="icon" alt=""/>' . "\n";
+ $icon = $gtree->get_element_icon($element);
$last = '';
- $catcourseitem = false;
-
- switch ($type) {
- case 'item':
- if ($object->itemtype == 'mod') {
- $icon = '<img src="'.$CFG->modpixpath.'/'.$object->itemmodule.'/icon.gif" class="icon" alt="'
- . get_string('modulename', $object->itemmodule).'"/>' . "\n";
- } else if ($object->itemtype == 'manual') {
- //TODO: add manual grading icon
- if (empty($object->outcomeid)) {
- $icon = '<img src="'.$CFG->pixpath.'/t/edit.gif" class="icon" alt="'
- . get_string('manualgrade', 'grades').'"/>' . "\n"; // TODO: localize
- } else {
- $icon = '<img src="'.$CFG->pixpath.'/i/outcomes.gif" class="icon" alt="'
- . get_string('outcome', 'grades').'"/>' . "\n";
- }
- }
- break;
- case 'courseitem':
- case 'categoryitem':
- $icon = '<img src="'.$CFG->pixpath.'/i/category_grade.gif" class="icon" alt="'.get_string('categorygrade').'"/>' . "\n"; // TODO: localize
- $catcourseitem = true;
- break;
- case 'category':
- $icon = '<img src="'.$CFG->pixpath.'/f/folder.gif" class="icon" alt="'.get_string('category').'"/>' . "\n";
- break;
- }
+ $catcourseitem = ($element['type'] == 'courseitem' or $element['type'] == 'categoryitem');
if ($type != 'category') {
$return_string .= '<li class="'.$type.'">'.$icon.$name.'</li>' . "\n";
GRADE_AGGREGATE_EXTRACREDIT_MEAN=>get_string('aggregateextracreditmean', 'grades'));
// visible elements
- $mform->addElement('header', 'general', get_string('gradecategory', 'grades'));
+ $mform->addElement('header', 'gradecat', get_string('gradecategory', 'grades'));
$mform->addElement('text', 'fullname', get_string('categoryname', 'grades'));
if ($CFG->grade_aggregation == -1) {
$mform->addElement('static', 'aggregateonlygraded', get_string('aggregateonlygraded', 'grades'));
}
- if (!empty($CFG->enableoutcomes) && $CFG->grade_aggregateoutcomes == -1) {
- $mform->addElement('advcheckbox', 'aggregateoutcomes', get_string('aggregateoutcomes', 'grades'));
- $mform->setHelpButton('aggregateoutcomes', array(false, get_string('aggregateoutcomes', 'grades'),
- false, true, false, get_string('aggregateoutcomeshelp', 'grades')));
- } else {
- $mform->addElement('static', 'aggregateoutcomes', get_string('aggregateoutcomes', 'grades'));
+ if (!empty($CFG->enableoutcomes)) {
+ if($CFG->grade_aggregateoutcomes == -1) {
+ $mform->addElement('advcheckbox', 'aggregateoutcomes', get_string('aggregateoutcomes', 'grades'));
+ $mform->setHelpButton('aggregateoutcomes', array(false, get_string('aggregateoutcomes', 'grades'),
+ false, true, false, get_string('aggregateoutcomeshelp', 'grades')));
+ } else {
+ $mform->addElement('static', 'aggregateoutcomes', get_string('aggregateoutcomes', 'grades'));
+ }
}
if ($CFG->grade_aggregatesubcats == -1) {
}
// user preferences
- $mform->addElement('header', 'general', get_string('userpreferences', 'grades'));
+ $mform->addElement('header', 'userpref', get_string('myreportpreferences', 'grades'));
$options = array(GRADE_REPORT_PREFERENCE_DEFAULT => get_string('default', 'grades'),
GRADE_REPORT_AGGREGATION_VIEW_FULL => get_string('fullmode', 'grades'),
GRADE_REPORT_AGGREGATION_VIEW_AGGREGATES_ONLY => get_string('aggregatesonly', 'grades'),
$agg_el->setValue($checkbox_values[$CFG->grade_aggregateonlygraded]);
}
- if ($CFG->grade_aggregateoutcomes != -1) {
- $agg_el =& $mform->getElement('aggregateoutcomes');
- $agg_el->setValue($checkbox_values[$CFG->grade_aggregateoutcomes]);
+ if (!empty($CFG->enableoutcomes)) {
+ if ($CFG->grade_aggregateoutcomes != -1) {
+ $agg_el =& $mform->getElement('aggregateoutcomes');
+ $agg_el->setValue($checkbox_values[$CFG->grade_aggregateoutcomes]);
+ }
}
if ($CFG->grade_aggregatesubcats != -1) {
$actions .= $gtree->get_hiding_icon($element, $gpr);
/// prepare icon
- $icon = '<img src="'.$CFG->wwwroot.'/pix/spacer.gif" class="icon" alt=""/>';
+ $icon = $gtree->get_element_icon($element);
$last = '';
- $catcourseitem = false;
- switch ($element['type']) {
- case 'item':
- if ($object->itemtype == 'mod') {
- $icon = '<img src="'.$CFG->modpixpath.'/'.$object->itemmodule.'/icon.gif" class="icon" alt="'
- . get_string('modulename', $object->itemmodule).'"/>';
- } else if ($object->itemtype == 'manual') {
- //TODO: add manual grading icon
- if (empty($object->outcomeid)) {
- $icon = '<img src="'.$CFG->pixpath.'/t/edit.gif" class="icon" alt="'
- . get_string('manualgrade', 'grades').'"/>'; // TODO: localize
- } else {
- $icon = '<img src="'.$CFG->pixpath.'/i/outcomes.gif" class="icon" alt="'
- . get_string('outcome', 'grades').'"/>';
-
- }
- }
- break;
- case 'courseitem':
- case 'categoryitem':
- $icon = '<img src="'.$CFG->pixpath.'/i/category_grade.gif" class="icon" alt="'.get_string('categorygrade').'"/>'; // TODO: localize
- $catcourseitem = true;
- break;
- case 'category':
- $icon = '<img src="'.$CFG->pixpath.'/f/folder.gif" class="icon" alt="'.get_string('category').'"/>';
- break;
- }
+ $catcourseitem = ($element['type'] == 'courseitem' or $element['type'] == 'categoryitem');
/// prepare move target if needed
$moveto = '';
return 'g'.$grade_grade->id;
}
}
-
}
/**
}
grade_tree::fill_levels($this->levels, $this->top_element, 0);
+
}
/**
return $calculation_icon;
}
+
+ /**
+ * Returns icon of element
+ * @param object $element
+ * @param bool $spacerifnone return spacer if no icon found
+ * @return string icon or spacer
+ */
+ function get_element_icon(&$element, $spacerifnone=true) {
+ global $CFG;
+
+ switch ($element['type']) {
+ case 'item':
+ case 'courseitem':
+ case 'categoryitem':
+ if ($element['object']->is_calculated()) {
+ return '<img src="'.$CFG->pixpath.'/i/calc.gif" class="icon" alt="'.get_string('calculation', 'grades').'"/>';
+
+ } else if (($element['object']->is_course_item() or $element['object']->is_category_item())
+ and ($element['object']->gradetype == GRADE_TYPE_SCALE or $element['object']->gradetype == GRADE_TYPE_VALUE)) {
+ if ($category = $element['object']->get_item_category()) {
+ switch ($category->aggregation) {
+ case GRADE_AGGREGATE_MEAN:
+ case GRADE_AGGREGATE_MEDIAN:
+ case GRADE_AGGREGATE_WEIGHTED_MEAN:
+ case GRADE_AGGREGATE_EXTRACREDIT_MEAN:
+ return '<img src="'.$CFG->pixpath.'/i/agg_mean.gif" class="icon" alt="'.get_string('aggregation', 'grades').'"/>';
+ //case GRADE_AGGREGATE_SUM:
+ //return '<img src="'.$CFG->pixpath.'/i/agg_sum.gif" class="icon" alt="'.get_string('aggregation', 'grades').'"/>';
+ }
+ }
+
+ } else if ($element['object']->itemtype == 'mod') {
+ return '<img src="'.$CFG->modpixpath.'/'.$element['object']->itemmodule.'/icon.gif" class="icon" alt="'
+ .get_string('modulename', $element['object']->itemmodule).'"/>';
+
+ } else if ($element['object']->itemtype == 'manual') {
+ if ($element['object']->is_outcome_item()) {
+ return '<img src="'.$CFG->pixpath.'/i/outcomes.gif" class="icon" alt="'.get_string('outcome', 'grades').'"/>';
+ } else {
+ //TODO: add better icon
+ return '<img src="'.$CFG->pixpath.'/t/edit.gif" class="icon" alt="'.get_string('manualitem', 'grades').'"/>';
+ }
+ }
+ break;
+
+ case 'category':
+ return '<img src="'.$CFG->pixpath.'/f/folder.gif" class="icon" alt="'.get_string('category', 'grades').'"/>';
+ }
+
+ if ($spacerifnone) {
+ return '<img src="'.$CFG->wwwroot.'/pix/spacer.gif" class="icon" alt=""/>';
+ } else {
+ return '';
+ }
+ }
}
?>
}
$report->load_users();
+
+
$numusers = $report->get_numusers();
$report->load_final_grades();
$userids = array_keys($this->users);
+
if ($grades = get_records_sql($sql)) {
foreach ($grades as $graderec) {
- if (in_array($graderec->userid, $userids)) {
+ if (in_array($graderec->userid, $userids) and array_key_exists($graderec->itemid, $this->gtree->items)) { // some items may not be present!!
$this->grades[$graderec->userid][$graderec->itemid] = new grade_grade($graderec, false);
$this->grades[$graderec->userid][$graderec->itemid]->grade_item =& $this->gtree->items[$graderec->itemid]; // db caching
}
*/
function get_studentshtml() {
global $CFG, $USER;
+
$studentshtml = '';
- $strfeedback = $this->get_lang_string("feedback");
- $strgrade = $this->get_lang_string('grade');
+ $strfeedback = $this->get_lang_string("feedback");
+ $strgrade = $this->get_lang_string('grade');
$gradetabindex = 1;
$showuserimage = $this->get_pref('showuserimage');
- $numusers = count($this->users);
+ $numusers = count($this->users);
// Preload scale objects for items with a scaleid
$scales_list = '';
$tabindices = array();
+
foreach ($this->gtree->items as $item) {
if (!empty($item->scaleid)) {
$scales_list .= "$item->scaleid,";
}
+
$tabindices[$item->id]['grade'] = $gradetabindex;
$tabindices[$item->id]['feedback'] = $gradetabindex + $numusers;
$gradetabindex += $numusers * 2;
foreach ($this->users as $userid => $user) {
if ($canviewhidden) {
- $hiding_affected = array();
+ $altered = array();
+ $unknown = array();
} else {
$hiding_affected = grade_grade::get_hiding_affected($this->grades[$userid], $this->gtree->items);
+ $altered = $hiding_affected['altered'];
+ $unknown = $hiding_affected['unknown'];
+ unset($hiding_affected);
}
$columncount = 0;
foreach ($this->gtree->items as $itemid=>$unused) {
$item =& $this->gtree->items[$itemid];
+ $grade = $this->grades[$userid][$item->id];
// Get the decimal points preference for this item
$decimalpoints = $item->get_decimals();
- $grade = $this->grades[$userid][$item->id];
- $gradeval = $grade->finalgrade;
+ if (in_array($itemid, $unknown)) {
+ $gradeval = null;
+ } else if (array_key_exists($itemid, $altered)) {
+ $gradeval = $altered[$itemid];
+ } else {
+ $gradeval = $grade->finalgrade;
+ }
// MDL-11274
// Hide grades in the grader report if the current grader doesn't have 'moodle/grade:viewhidden'
- if (!$canviewhidden and ($grade->is_hidden() or in_array($itemid, $hiding_affected))) {
- if (!is_null($gradeval) and $grade->is_hidden()) {
+ if (!$canviewhidden and $grade->is_hidden()) {
+ if (!empty($CFG->grade_hiddenasdate) and !is_null($grade->finalgrade) and !$item->is_category_item() and !$item->is_course_item()) {
+ // the problem here is that we do not have the time when grade value was modified, 'timemodified' is general modification date for grade_grades records
$studentshtml .= '<td class="cell c'.$columncount++.'">'.userdate($grade->timecreated,get_string('strftimedatetimeshort')).'</td>';
} else {
$studentshtml .= '<td class="cell c'.$columncount++.'">-</td>';
}
if ($canviewhidden) {
- $hiding_affected = array();
+ $altered = array();
+ $unknown = array();
} else {
$hiding_affected = grade_grade::get_hiding_affected($grades, $items);
+ $altered = $hiding_affected['altered'];
+ $unknown = $hiding_affected['unknown'];
+ unset($hiding_affected);
}
- foreach ($items as $key=>$unused) {
- $grade_item =& $items[$key];
- $grade_grade =& $grades[$key];
+ foreach ($items as $itemid=>$unused) {
+ $grade_item =& $items[$itemid];
+ $grade_grade =& $grades[$itemid];
+
+ if (in_array($itemid, $unknown)) {
+ $gradeval = null;
+ } else if (array_key_exists($itemid, $altered)) {
+ $gradeval = $altered[$itemid];
+ } else {
+ $gradeval = $grade_grade->finalgrade;
+ }
$data = array();
if ($grade_item->needsupdate) {
$data[] = '<span class="gradingerror">'.get_string('error').'</span>';
- } else if (is_null($grade_grade->finalgrade)) {
- $data[] = $excluded . '-';
-
- } else if (!$canviewhidden and ($grade_grade->is_hidden() or in_array($grade_item->id, $hiding_affected))) {
- // TODO: optinally do not show anything for hidden grades
- // $data[] = '-';
- if ($grade_grade->is_hidden()) {
- $data[] = $excluded . '<div class="gradeddate">'.get_string('gradedon', 'grades', userdate($grade_grade->timemodified, get_string('strftimedatetimeshort'))).'</div>';
- } else {
- $data[] = $excluded . '-';
- }
+ } else if (!empty($CFG->grade_hiddenasdate) and !is_null($grade_grade->finalgrade) and !$canviewhidden and $grade_grade->is_hidden()
+ and !$grade_item->is_category_item() and !$grade_item->is_course_item()) {
+ // the problem here is that we do not have the time when grade value was modified, 'timemodified' is general modification date for grade_grades records
+ $data[] = $excluded . '<div class="gradeddate">'.get_string('gradedon', 'grades', userdate($grade_grade->timemodified, get_string('strftimedatetimeshort'))).'</div>';
} else {
- $data[] = $excluded . grade_format_gradevalue($grade_grade->finalgrade, $grade_item, true);
+ $data[] = $excluded . grade_format_gradevalue($gradeval, $grade_item, true);
}
/// prints percentage
if ($grade_item->needsupdate) {
$data[] = '<span class="gradingerror">'.get_string('error').'</span>';
- } else if (is_null($grade_grade->finalgrade)) {
- $data[] = '-';
-
- } else if (!$canviewhidden and ($grade_grade->is_hidden() or in_array($grade_item->id, $hiding_affected))) {
- $data[] = '-';
-
} else {
- $data[] = grade_format_gradevalue($grade_grade->finalgrade, $grade_item, true, GRADE_DISPLAY_TYPE_PERCENTAGE);
+ $data[] = grade_format_gradevalue($gradeval, $grade_item, true, GRADE_DISPLAY_TYPE_PERCENTAGE);
}
/// prints rank
if ($grade_item->needsupdate) {
$data[] = '<span class="gradingerror">'.get_string('error').'</span>';
- } else if (is_null($grade_grade->finalgrade)) {
+ } else if (is_null($gradeval)) {
// no grade, no rank
$data[] = '-';
- } else if (!$canviewhidden and ($grade_grade->is_hidden() or in_array($grade_item->id, $hiding_affected))) {
- $data[] = '-';
-
} else {
/// find the number of users with a higher grade
$sql = "SELECT COUNT(DISTINCT(userid))
if (empty($grade_grade->feedback)) {
$data[] = ' ';
- } else if (!$canviewhidden and ($grade_grade->is_hidden() or in_array($grade_item->id, $hiding_affected))) {
+ } else if (!$canviewhidden and $grade_grade->is_hidden()) {
$data[] = ' ';
} else {
$string['configgradeletter'] = 'A letter or other symbol used to represent a range of grades.';
$string['configgradeletterdefault'] = 'A letter or other symbol used to represent a range of grades. Leave this field empty to use the site default (currently $a).';
$string['configgradepublishing'] = 'Enable publishing in exports and imports: Exported grades can be accessed by accessing a URL, without having to log on to a Moodle site. Grades can be imported by accessing such a URL (which means that a moodle site can import grades published by another site). By default only administrators may use this feature, please educate users before adding required capabilities to other roles (dangers of bookmark sharing and download accelerators, IP restrictions, etc.).';
+$string['confighiddenasdate'] = 'If user can not see hidden grades show date instead of \'-\'.';
$string['configmeanselection'] = 'Select which types of grades will be included in the column averages. Cells with no grade can be ignored, or counted as 0 (default setting).';
$string['configquickfeedback'] = 'Quick Feedback adds a text input element in each grade cell on the grader report, allowing you to edit many grades at once. You can then click the Update button to perform all these changes at once, instead of one at a time.';
$string['configquickgrading'] = 'Quick Grading adds a text input element in each grade cell on the grader report, allowing you to edit the feedback for many grades at once. You can then click the Update button to perform all these changes at once, instead of one at a time.';
$string['gradecategories'] = 'Grade categories';
$string['gradecategory'] = 'Grade Category';
$string['gradecategoryhelp'] = 'Grade Category Help';
-$string['gradecategorysettings'] = 'Grade Category Settings';
+$string['gradecategorysettings'] = 'Grade category settings';
$string['gradedon'] = 'Graded $a';
$string['gradedisplay'] = 'Grade display';
$string['gradedisplaytype'] = 'Grade display type';
$string['gradeweighthelp'] = 'Grade Weight Help';
$string['groupavg'] = 'Group average';
$string['hidden'] = 'Hidden';
+$string['hiddenasdate'] = 'Show date for hidden grades';
$string['hiddenuntil'] = 'Hidden until';
$string['hiddenuntildate'] = 'Hidden until: $a';
$string['hideadvanced'] = 'Hide Advanced Features';
$string['locktimedate'] = 'Locked after: $a';
$string['lowest'] = 'Lowest';
$string['lowgradeletter'] = 'Low';
+$string['manualitem'] = 'Manual item';
$string['mapfrom'] = 'Map from';
$string['mapto'] = 'Map to';
$string['max'] = 'Highest';
return;
}
- /// start the aggregation
+ // do the maths
+ $agg_grade = $this->aggregate_values($grade_values, $items);
+
+ /// prepare update of new raw grade
+ $grade->rawgrademin = $this->grade_item->grademin;
+ $grade->rawgrademax = $this->grade_item->grademax;
+ $grade->rawscaleid = $this->grade_item->scaleid;
+ $grade->rawgrade = null; // categories do not use raw grades
+
+ // recalculate the rawgrade back to requested range
+ $finalgrade = grade_grade::standardise_score($agg_grade, 0, 1, $this->grade_item->grademin, $this->grade_item->grademax);
+
+ if (!is_null($finalgrade)) {
+ $grade->finalgrade = bounded_number($this->grade_item->grademin, $finalgrade, $this->grade_item->grademax);
+ } else {
+ $grade->finalgrade = $finalgrade;
+ }
+
+ // update in db if changed
+ if ( $grade->finalgrade !== $oldgrade->finalgrade
+ or $grade->rawgrade !== $oldgrade->rawgrade
+ or $grade->rawgrademin !== $oldgrade->rawgrademin
+ or $grade->rawgrademax !== $oldgrade->rawgrademax
+ or $grade->rawscaleid !== $oldgrade->rawscaleid) {
+
+ $grade->update('system');
+ }
+
+ return;
+ }
+
+ function aggregate_values($grade_values, $items) {
switch ($this->aggregation) {
case GRADE_AGGREGATE_MEDIAN: // Middle point value in the set: ignores frequencies
$num = count($grade_values);
break;
}
- /// prepare update of new raw grade
- $grade->rawgrademin = $this->grade_item->grademin;
- $grade->rawgrademax = $this->grade_item->grademax;
- $grade->rawscaleid = $this->grade_item->scaleid;
- $grade->rawgrade = null; // categories do not use raw grades
-
- // recalculate the rawgrade back to requested range
- $finalgrade = grade_grade::standardise_score($agg_grade, 0, 1, $this->grade_item->grademin, $this->grade_item->grademax);
-
- if (!is_null($finalgrade)) {
- $grade->finalgrade = bounded_number($this->grade_item->grademin, $finalgrade, $this->grade_item->grademax);
- } else {
- $grade->finalgrade = $finalgrade;
- }
-
- // update in db if changed
- if ( $grade->finalgrade !== $oldgrade->finalgrade
- or $grade->rawgrade !== $oldgrade->rawgrade
- or $grade->rawgrademin !== $oldgrade->rawgrademin
- or $grade->rawgrademax !== $oldgrade->rawgrademax
- or $grade->rawscaleid !== $oldgrade->rawscaleid) {
-
- $grade->update('system');
- }
-
- return;
+ return $agg_grade;
}
-
/**
* Given an array of grade values (numerical indices), applies droplow or keephigh
* rules to limit the final array.
* Returns array of grades for given grade_item+users.
* @param object $grade_item
* @param array $userids
- * @param bool $include_missing include grades taht do not exist yet
+ * @param bool $include_missing include grades that do not exist yet
* @return array userid=>grade_grade array
*/
function fetch_users_grades($grade_item, $userids, $include_missing=true) {
/**
* Return array of grade item ids that are either hidden or indirectly depend
* on hidden grades, excluded grades are not returned.
+ * THIS IS A REALLY BIG HACK! to be replaced by conditional aggregation of hidden grades in 2.0
+ *
* @static
* @param array $grades all course grades of one user, & used for better internal caching
* @param array $items $grade_items array of grade items, & used for better internal caching
* @return array
*/
function get_hiding_affected(&$grade_grades, &$grade_items) {
+ global $CFG;
+
if (count($grade_grades) !== count($grade_items)) {
error("Incorrent size of arrays in params of grade_grade::get_hiding_affected()!");
}
$dependson = array();
+ $todo = array();
+ $unknown = array(); // can not find altered
+ $altered = array(); // altered grades
+
foreach($grade_items as $key=>$unused) {
$grade_item =& $grade_items[$key]; // reference for improved caching inside grade_item
- $dependson[$grade_item->id] = $grade_item->depends_on();
+ $dependson[$grade_items[$key]->id] = $grade_items[$key]->depends_on();
}
- $todo = array();
- $hiding = array();
+ $hiddenfound = false;
foreach($grade_grades as $grade_grade) {
- if ($grade_grade->is_hidden() and !$grade_grade->is_excluded() and !is_null($grade_grade->finalgrade)) {
- $hiding[] = $grade_grade->itemid;
- } else {
+ if ($grade_grade->is_excluded()) {
+ //nothing to do, aggregation is ok
+ } else if ($grade_grade->is_hidden()) {
+ $hiddenfound = true;
+ // hidden null grade does not affect the aggregation
+ if (!is_null($grade_grade->finalgrade)) {
+ $altered[$grade_grade->itemid] = null;
+ }
+ } else if (!empty($dependson[$grade_grade->itemid])) {
$todo[] = $grade_grade->itemid;
}
}
+ if (!$hiddenfound) {
+ return array('unknown'=>array(), 'altered'=>array());
+ }
- $max = count($grade_items);
+ $max = count($todo);
for($i=0; $i<$max; $i++) {
$found = false;
foreach($todo as $key=>$do) {
- if (empty($dependson[$do])) {
- unset($todo[$key]);
- continue;
-
- } else if (array_intersect($dependson[$do], $hiding)) {
+ if (array_intersect($dependson[$do], $unknown)) {
// this item depends on hidden grade indirectly
- $hiding[] = $do;
+ $unknown[$do] = $do;
unset($todo[$key]);
$found = true;
+ continue;
+
+ } else if (!array_intersect($dependson[$do], $todo)) {
+ if (!array_intersect($dependson[$do], array_keys($altered))) {
+ // hiding does not affect this grade
+ unset($todo[$key]);
+ $found = true;
+ continue;
+
+ } else {
+ // depends on altered grades - we should try to recalculate if possible
+ if ($grade_items[$do]->is_calculated() or (!$grade_items[$do]->is_category_item() and !$grade_items[$do]->is_course_item())) {
+ $unknown[$do] = $do;
+ unset($todo[$key]);
+ $found = true;
+ continue;
+ } else {
+ $grade_category = $grade_items[$do]->load_item_category();
+ $values = array();
+ foreach ($dependson[$do] as $itemid) {
+ if (array_key_exists($itemid, $altered)) {
+ $values[$itemid] = $altered[$itemid];
+ } else {
+ $values[$itemid] = $grade_grades[$itemid]->finalgrade;
+ }
+ }
+ if ($CFG->grade_aggregateonlygraded != -1) {
+ $grade_category->aggregateonlygraded = $CFG->grade_aggregateonlygraded;
+ }
+
+ if ($grade_category->aggregateonlygraded) {
+ foreach ($values as $itemid=>$value) {
+ if (is_null($value)) {
+ unset($values[$itemid]);
+ }
+ }
+ } else {
+ foreach ($values as $itemid=>$value) {
+ if (is_null($value)) {
+ $values[$itemid] = $grade_items[$itemid]->grademin;
+ }
+ }
+ }
+ foreach ($values as $itemid=>$value) {
+ if ($grade_grades[$itemid]->is_excluded()) {
+ unset($values[$itemid]);
+ continue;
+ }
+ $values[$itemid] = grade_grade::standardise_score($value, $grade_items[$itemid]->grademin, $grade_items[$itemid]->grademax, 0, 1);
+ }
+
+ // limit and sort
+ $grade_category->apply_limit_rules($values);
+ asort($values, SORT_NUMERIC);
+
+ // let's see we have still enough grades to do any statistics
+ if (count($values) == 0) {
+ // not enough attempts yet
+ $altered[$do] = null;
+ unset($todo[$key]);
+ $found = true;
+ continue;
+ }
+
+ $agg_grade = $grade_category->aggregate_values($values, $grade_items);
+
+ // recalculate the rawgrade back to requested range
+ $finalgrade = grade_grade::standardise_score($agg_grade, 0, 1, $grade_items[$itemid]->grademin, $grade_items[$itemid]->grademax);
+
+ if (!is_null($finalgrade)) {
+ $finalgrade = bounded_number($grade_items[$itemid]->grademin, $finalgrade, $grade_items[$itemid]->grademax);
+ }
+
+ $altered[$do] = $finalgrade;
+ unset($todo[$key]);
+ $found = true;
+ continue;
+ }
+ }
}
}
if (!$found) {
}
}
- return $hiding;
+ return array('unknown'=>$unknown, 'altered'=>$altered);
}
}
?>