From d297269d798f6bd79eac6b5838c38bab4097b221 Mon Sep 17 00:00:00 2001 From: skodak Date: Fri, 19 Oct 2007 08:51:52 +0000 Subject: [PATCH] --- admin/settings/grades.php | 29 +++--- grade/edit/tree/calculation.php | 30 +----- grade/edit/tree/category_form.php | 26 +++-- grade/edit/tree/index.php | 30 +----- grade/lib.php | 57 +++++++++- grade/report/grader/index.php | 2 + grade/report/grader/lib.php | 33 ++++-- grade/report/user/lib.php | 52 +++++----- lang/en_utf8/grades.php | 5 +- lib/grade/grade_category.php | 61 ++++++----- lib/grade/grade_grade.php | 121 +++++++++++++++++++--- pix/i/agg_mean.gif | Bin 0 -> 117 bytes pix/i/{category_grade.gif => agg_sum.gif} | Bin 13 files changed, 284 insertions(+), 162 deletions(-) create mode 100644 pix/i/agg_mean.gif rename pix/i/{category_grade.gif => agg_sum.gif} (100%) diff --git a/admin/settings/grades.php b/admin/settings/grades.php index 69b013add8..0d6fbe1be8 100644 --- a/admin/settings/grades.php +++ b/admin/settings/grades.php @@ -10,8 +10,6 @@ $temp = new admin_settingpage('gradessettings', get_string('gradessettings', 'gr // 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, @@ -33,6 +31,11 @@ $temp->add(new admin_setting_configselect('grade_decimalpoints', get_string('dec '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'), @@ -46,20 +49,11 @@ $temp->add(new admin_setting_configselect('grade_export_decimalpoints', get_stri '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')); @@ -96,6 +90,15 @@ $temp->add(new admin_setting_configselect('grade_droplow', get_string('droplow', $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 diff --git a/grade/edit/tree/calculation.php b/grade/edit/tree/calculation.php index 39caceadc7..f7fce260d3 100644 --- a/grade/edit/tree/calculation.php +++ b/grade/edit/tree/calculation.php @@ -187,35 +187,9 @@ function get_grade_tree(&$gtree, $element, $current_itemid=null, $errors=null) { } } - $icon = '' . "\n"; + $icon = $gtree->get_element_icon($element); $last = ''; - $catcourseitem = false; - - switch ($type) { - case 'item': - if ($object->itemtype == 'mod') { - $icon = ''
-                      . get_string('modulename', $object->itemmodule).'' . "\n"; - } else if ($object->itemtype == 'manual') { - //TODO: add manual grading icon - if (empty($object->outcomeid)) { - $icon = ''
-                          . get_string('manualgrade', 'grades').'' . "\n"; // TODO: localize - } else { - $icon = ''
-                          . get_string('outcome', 'grades').'' . "\n"; - } - } - break; - case 'courseitem': - case 'categoryitem': - $icon = ''.get_string('categorygrade').'' . "\n"; // TODO: localize - $catcourseitem = true; - break; - case 'category': - $icon = ''.get_string('category').'' . "\n"; - break; - } + $catcourseitem = ($element['type'] == 'courseitem' or $element['type'] == 'categoryitem'); if ($type != 'category') { $return_string .= '
  • '.$icon.$name.'
  • ' . "\n"; diff --git a/grade/edit/tree/category_form.php b/grade/edit/tree/category_form.php index ec80f54941..59d7ea0bcb 100644 --- a/grade/edit/tree/category_form.php +++ b/grade/edit/tree/category_form.php @@ -42,7 +42,7 @@ class edit_category_form extends moodleform { 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) { @@ -62,12 +62,14 @@ class edit_category_form extends moodleform { $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) { @@ -111,7 +113,7 @@ class edit_category_form extends moodleform { } // 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'), @@ -158,9 +160,11 @@ class edit_category_form extends moodleform { $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) { diff --git a/grade/edit/tree/index.php b/grade/edit/tree/index.php index ad217aced3..30092d426d 100644 --- a/grade/edit/tree/index.php +++ b/grade/edit/tree/index.php @@ -201,35 +201,9 @@ function print_grade_tree(&$gtree, $element, $moving, &$gpr, $switch, $switchedl $actions .= $gtree->get_hiding_icon($element, $gpr); /// prepare icon - $icon = ''; + $icon = $gtree->get_element_icon($element); $last = ''; - $catcourseitem = false; - switch ($element['type']) { - case 'item': - if ($object->itemtype == 'mod') { - $icon = ''
-                      . get_string('modulename', $object->itemmodule).''; - } else if ($object->itemtype == 'manual') { - //TODO: add manual grading icon - if (empty($object->outcomeid)) { - $icon = ''
-                          . get_string('manualgrade', 'grades').''; // TODO: localize - } else { - $icon = ''
-                          . get_string('outcome', 'grades').''; - - } - } - break; - case 'courseitem': - case 'categoryitem': - $icon = ''.get_string('categorygrade').''; // TODO: localize - $catcourseitem = true; - break; - case 'category': - $icon = ''.get_string('category').''; - break; - } + $catcourseitem = ($element['type'] == 'courseitem' or $element['type'] == 'categoryitem'); /// prepare move target if needed $moveto = ''; diff --git a/grade/lib.php b/grade/lib.php index d60ef42bd8..c217ddaf0f 100644 --- a/grade/lib.php +++ b/grade/lib.php @@ -839,7 +839,6 @@ class grade_seq { return 'g'.$grade_grade->id; } } - } /** @@ -919,6 +918,7 @@ class grade_tree { } grade_tree::fill_levels($this->levels, $this->top_element, 0); + } /** @@ -1344,6 +1344,61 @@ class grade_tree { 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 ''.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 ''.get_string('aggregation', 'grades').''; + //case GRADE_AGGREGATE_SUM: + //return ''.get_string('aggregation', 'grades').''; + } + } + + } else if ($element['object']->itemtype == 'mod') { + return ''
+                           .get_string('modulename', $element['object']->itemmodule).''; + + } else if ($element['object']->itemtype == 'manual') { + if ($element['object']->is_outcome_item()) { + return ''.get_string('outcome', 'grades').''; + } else { + //TODO: add better icon + return ''.get_string('manualitem', 'grades').''; + } + } + break; + + case 'category': + return ''.get_string('category', 'grades').''; + } + + if ($spacerifnone) { + return ''; + } else { + return ''; + } + } } ?> diff --git a/grade/report/grader/index.php b/grade/report/grader/index.php index 4576e518ea..ec0e8a30b2 100644 --- a/grade/report/grader/index.php +++ b/grade/report/grader/index.php @@ -132,6 +132,8 @@ if ($perpageurl) { } $report->load_users(); + + $numusers = $report->get_numusers(); $report->load_final_grades(); diff --git a/grade/report/grader/lib.php b/grade/report/grader/lib.php index 20f2ab403c..403fcece53 100644 --- a/grade/report/grader/lib.php +++ b/grade/report/grader/lib.php @@ -342,9 +342,10 @@ class grade_report_grader extends grade_report { $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 } @@ -603,20 +604,23 @@ class grade_report_grader extends grade_report { */ 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; @@ -633,9 +637,13 @@ class grade_report_grader extends grade_report { 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; @@ -651,17 +659,24 @@ class grade_report_grader extends grade_report { 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 .= ''.userdate($grade->timecreated,get_string('strftimedatetimeshort')).''; } else { $studentshtml .= '-'; diff --git a/grade/report/user/lib.php b/grade/report/user/lib.php index 4d7933a916..da4c6b1afa 100644 --- a/grade/report/user/lib.php +++ b/grade/report/user/lib.php @@ -137,14 +137,26 @@ class grade_report_user extends grade_report { } 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(); @@ -169,47 +181,31 @@ class grade_report_user extends grade_report { if ($grade_item->needsupdate) { $data[] = ''.get_string('error').''; - } 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 . '
    '.get_string('gradedon', 'grades', userdate($grade_grade->timemodified, get_string('strftimedatetimeshort'))).'
    '; - } 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 . '
    '.get_string('gradedon', 'grades', userdate($grade_grade->timemodified, get_string('strftimedatetimeshort'))).'
    '; } 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[] = ''.get_string('error').''; - } 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[] = ''.get_string('error').''; - } 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)) @@ -225,7 +221,7 @@ class grade_report_user extends grade_report { 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 { diff --git a/lang/en_utf8/grades.php b/lang/en_utf8/grades.php index 0462ad9312..efa0d1f24e 100644 --- a/lang/en_utf8/grades.php +++ b/lang/en_utf8/grades.php @@ -74,6 +74,7 @@ $string['configexportdecimalpoints'] = 'The number of decimal points to display $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.'; @@ -163,7 +164,7 @@ $string['gradeboundary'] = 'Letter grade boundary'; $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'; @@ -205,6 +206,7 @@ $string['gradeview'] = 'View Grade'; $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'; @@ -256,6 +258,7 @@ $string['locktime'] = 'Lock after'; $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'; diff --git a/lib/grade/grade_category.php b/lib/grade/grade_category.php index 7d0d33443e..8e66c5bd4a 100644 --- a/lib/grade/grade_category.php +++ b/lib/grade/grade_category.php @@ -521,7 +521,38 @@ class grade_category extends grade_object { 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); @@ -593,34 +624,8 @@ class grade_category extends grade_object { 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. diff --git a/lib/grade/grade_grade.php b/lib/grade/grade_grade.php index 3c02bf9f63..b1d83d618c 100644 --- a/lib/grade/grade_grade.php +++ b/lib/grade/grade_grade.php @@ -142,7 +142,7 @@ class grade_grade extends grade_object { * 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) { @@ -475,45 +475,136 @@ class grade_grade extends grade_object { /** * 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) { @@ -521,7 +612,7 @@ class grade_grade extends grade_object { } } - return $hiding; + return array('unknown'=>$unknown, 'altered'=>$altered); } } ?> diff --git a/pix/i/agg_mean.gif b/pix/i/agg_mean.gif new file mode 100644 index 0000000000000000000000000000000000000000..ed4c0fdb8ce00d7e9028200c0c7296cb4c7c1885 GIT binary patch literal 117 zcmZ?wbhEHb6krfwc+AW2{rmgJH&|v(WPJJj?Bp)S|Np$UZ`*O{7~{4L;cp%=<)re= zovNgzuKgbd6o0ZXaxw5T=r8~Q$P5M+r4J`PSMRk*K4yJg;j8E3s}uPb&rRgqwffew QPe<#v&N!S{@5*2e0Gr@8p#T5? literal 0 HcmV?d00001 diff --git a/pix/i/category_grade.gif b/pix/i/agg_sum.gif similarity index 100% rename from pix/i/category_grade.gif rename to pix/i/agg_sum.gif -- 2.39.5