From 7a6b7acf76847421fb0acf2ff3ff28fe4afb8a53 Mon Sep 17 00:00:00 2001 From: skodak Date: Tue, 24 Jul 2007 07:45:15 +0000 Subject: [PATCH] MDL-10579 more capability checks in grades code + refactoring of grade_tree --- grade/edit/action.php | 72 +++++ grade/edit/calculation.php | 2 +- grade/edit/category.php | 1 - grade/edit/grade.php | 1 - grade/edit/item.php | 2 +- grade/edit/tree.php | 83 ++---- grade/lib.php | 359 ++++++++++++++++++++++++- grade/report/grader/index.php | 2 +- grade/report/index.php | 2 +- grade/report/user/index.php | 10 +- lib/grade/grade_tree.php | 238 ---------------- lib/grade/simpletest/testgradetree.php | 50 ---- lib/gradelib.php | 1 - 13 files changed, 445 insertions(+), 378 deletions(-) create mode 100644 grade/edit/action.php delete mode 100644 lib/grade/grade_tree.php delete mode 100644 lib/grade/simpletest/testgradetree.php diff --git a/grade/edit/action.php b/grade/edit/action.php new file mode 100644 index 00000000000..f6b4eb2ec46 --- /dev/null +++ b/grade/edit/action.php @@ -0,0 +1,72 @@ +dirroot.'/grade/lib.php'; + +$courseid = required_param('id', PARAM_INT); +$action = required_param('action', PARAM_ALPHA); +$eid = required_param('eid', PARAM_ALPHANUM); + +/// Make sure they can even access this course +if (!$course = get_record('course', 'id', $courseid)) { + print_error('nocourseid'); +} +require_login($course); +$context = get_context_instance(CONTEXT_COURSE, $course->id); + +// default return url +$gpr = new grade_plugin_return(); +$returnurl = $gpr->get_return_url($CFG->wwwroot.'/grade/edit/tree.php?id='.$course->id); + +// get the grading tree object +$gtree = new grade_tree($courseid, false, false); + +// what are we working with? +if (!$element = $gtree->locate_element($eid)) { + error('Incorrect element id!', $returnurl); +} +$object = $element['object']; + + +switch ($action) { + case 'hide': + if ($eid and confirm_sesskey()) { + if (!has_capability('moodle/grade:manage', $context) and !has_capability('moodle/grade:hide', $context)) { + error('No permission to hide!', $returnurl); + } + $object->set_hidden(1); + } + break; + + case 'show': + if ($eid and confirm_sesskey()) { + if (!has_capability('moodle/grade:manage', $context) and !has_capability('moodle/grade:hide', $context)) { + error('No permission to show!', $returnurl); + } + $object->set_hidden(0); + } + break; + + case 'lock': + if ($eid and confirm_sesskey()) { + if (!has_capability('moodle/grade:manage', $context) and !has_capability('moodle/grade:lock', $context)) { + error('No permission to lock!', $returnurl); + } + $object->set_locked(1); + } + break; + + case 'unlock': + if ($eid and confirm_sesskey()) { + if (!has_capability('moodle/grade:manage', $context) and !has_capability('moodle/grade:unlock', $context)) { + error('No permission to unlock!', $returnurl); + } + $object->set_locked(0); + } + break; +} + +redirect($returnurl); +//redirect($returnurl, 'debug delay', 5); + +?> \ No newline at end of file diff --git a/grade/edit/calculation.php b/grade/edit/calculation.php index 36e0af573b4..889cf4e46b5 100644 --- a/grade/edit/calculation.php +++ b/grade/edit/calculation.php @@ -1,7 +1,7 @@ dirroot.'/grade/lib.php'; -require_once $CFG->libdir.'/gradelib.php'; require_once 'calculation_form.php'; $courseid = required_param('courseid', PARAM_INT); diff --git a/grade/edit/category.php b/grade/edit/category.php index 81a9f4a3518..e5c6ec7e6e3 100644 --- a/grade/edit/category.php +++ b/grade/edit/category.php @@ -3,7 +3,6 @@ require_once '../../config.php'; require_once $CFG->dirroot.'/grade/lib.php'; require_once $CFG->dirroot.'/grade/report/lib.php'; -require_once $CFG->libdir.'/gradelib.php'; require_once 'category_form.php'; $courseid = required_param('courseid', PARAM_INT); diff --git a/grade/edit/grade.php b/grade/edit/grade.php index 63d15ddd188..f49044979ec 100644 --- a/grade/edit/grade.php +++ b/grade/edit/grade.php @@ -2,7 +2,6 @@ require_once '../../config.php'; require_once $CFG->dirroot.'/grade/lib.php'; -require_once $CFG->libdir.'/gradelib.php'; require_once 'grade_form.php'; $courseid = required_param('courseid', PARAM_INT); diff --git a/grade/edit/item.php b/grade/edit/item.php index 15796c88476..c25392c0dc7 100644 --- a/grade/edit/item.php +++ b/grade/edit/item.php @@ -1,8 +1,8 @@ dirroot.'/grade/lib.php'; require_once $CFG->dirroot.'/grade/report/lib.php'; -require_once $CFG->libdir.'/gradelib.php'; require_once 'item_form.php'; $courseid = required_param('courseid', PARAM_INT); diff --git a/grade/edit/tree.php b/grade/edit/tree.php index ae304ae1e41..1810c3cd55d 100644 --- a/grade/edit/tree.php +++ b/grade/edit/tree.php @@ -1,5 +1,4 @@ -dirroot.'/grade/lib.php'; -require_once $CFG->libdir.'/gradelib.php'; $courseid = required_param('id', PARAM_INT); $action = optional_param('action', 0, PARAM_ALPHA); @@ -40,12 +38,15 @@ if (!$course = get_record('course', 'id', $courseid)) { } require_login($course); - $context = get_context_instance(CONTEXT_COURSE, $course->id); -//require_capability() here!! +require_capability('moodle/grade:manage', $context); -// default return url -$returnurl = 'tree.php?id='.$course->id; +/// return tracking object +$gpr = new grade_plugin_return(array('type'=>'edit', 'courseid'=>$courseid)); +$returnurl = $gpr->get_return_url(null); + +//first make sure we have proper final grades - we need it for locking changes +grade_regrade_final_grades($courseid); // get the grading tree object // note: total must be first for moving to work correctly, if you want it last moving code must be rewritten! @@ -59,7 +60,7 @@ if (empty($eid)) { if (!$element = $gtree->locate_element($eid)) { error('Incorrect element id!', $returnurl); } - $object = $element['object']; + $object = $element['object']; } @@ -74,16 +75,6 @@ $navigation = build_navigation($nav); $moving = false; switch ($action) { - case 'edit': - if ($eid and confirm_sesskey()) { - if ($element['type'] == 'category') { - redirect('category.php?courseid='.$course->id.'&id='.$object->id); - } else { - redirect('item.php?courseid='.$course->id.'&id='.$object->id); - } - } - break; - case 'delete': if ($eid) { $confirm = optional_param('confirm', 0, PARAM_BOOL); @@ -135,35 +126,6 @@ switch ($action) { } break; - case 'hide': - if ($eid and confirm_sesskey()) { - $object->set_hidden(1); - redirect($returnurl); - } - break; - - case 'show': - if ($eid and confirm_sesskey()) { - $object->set_hidden(0); - redirect($returnurl); - } - break; - - case 'lock': - if ($eid and confirm_sesskey()) { - //TODO: add error handling in redirect - $object->set_locked(1); - redirect($returnurl); - } - break; - - case 'unlock': - if ($eid and confirm_sesskey()) { - $object->set_locked(0); - redirect($returnurl); - } - break; - default: break; } @@ -178,7 +140,7 @@ print_heading(get_string('categoriesedit', 'grades')); print_box_start('gradetreebox generalbox'); echo ''; print_box_end(); @@ -198,43 +160,32 @@ die; -function print_grade_tree($element, $moving) { +function print_grade_tree(&$gtree, $element, $moving, &$gpr) { global $CFG, $COURSE; /// fetch needed strings $strmove = get_string('move'); $strmovehere = get_string('movehere'); - $stredit = get_string('edit'); $strdelete = get_string('delete'); - $strhide = get_string('hide'); - $strshow = get_string('show'); - $strlock = get_string('lock', 'grades'); - $strunlock = get_string('unlock', 'grades'); $object = $element['object']; $eid = $element['eid']; /// prepare actions - $actions = ''.$stredit.''; + $actions = $gtree->get_edit_icon($element, $gpr); if ($element['type'] == 'item' or ($element['type'] == 'category' and $element['depth'] > 1)) { $actions .= ''.$strdelete.''; $actions .= ''.$strmove.''; } - if ($object->is_locked()) { - $actions .= ''.$strunlock.''; - } else { - $actions .= ''.$strlock.''; - } + $actions .= $gtree->get_locking_icon($element, $gpr); + $name = $object->get_name(); if ($object->is_hidden()) { - $name = ''.$object->get_name().''; - $actions .= ''.$strshow.''; - } else { - $name = $object->get_name(); - $actions .= ''.$strhide.''; + $name = ''.$name.''; } + $actions .= $gtree->get_hiding_icon($element, $gpr); /// prepare icon $icon = ''; @@ -275,7 +226,7 @@ function print_grade_tree($element, $moving) { echo '
  • '.$icon.$name.$actions; echo '
  • '; if ($element['depth'] > 1) { diff --git a/grade/lib.php b/grade/lib.php index a7d15b005ed..86dcadc92c0 100644 --- a/grade/lib.php +++ b/grade/lib.php @@ -1,5 +1,7 @@ libdir.'/gradelib.php'; + /** * Print grading plugin selection popup form. * @@ -91,7 +93,7 @@ function print_grade_plugin_selector($courseid, $active_type, $active_plugin, $r } /// editing scripts - not real plugins - if (true) { //TODO: add proper capability here + if (has_capability('moodle/grade:manage', $context)) { //TODO: add proper capability here $menu['edit']='--'.get_string('edit'); $url = 'edit/tree.php?id='.$courseid; if ($active_type == 'edit' and $active_plugin == 'tree' ) { @@ -105,7 +107,7 @@ function print_grade_plugin_selector($courseid, $active_type, $active_plugin, $r } /** - * Utility class used for return tracking when using edit and other forms from grade plubins + * Utility class used for return tracking when using edit and other forms in grade plugins */ class grade_plugin_return { var $type; @@ -140,13 +142,15 @@ class grade_plugin_return { * @return array options */ function get_options() { - if (empty($this->type) or empty($this->plugin)) { + if (empty($this->type)) { return array(); } $params = array(); - $params['plugin'] = $this->plugin; + if (!empty($this->plugin)) { + $params['plugin'] = $this->plugin; + } if (!empty($this->courseid)) { $params['id'] = $this->courseid; @@ -171,6 +175,10 @@ class grade_plugin_return { function get_return_url($default, $extras=null) { global $CFG; + if ($this->type == 'edit') { + return $CFG->wwwroot.'/grade/edit/tree.php?id='.$this->courseid; + } + if (empty($this->type) or empty($this->plugin)) { return $default; } @@ -197,7 +205,7 @@ class grade_plugin_return { foreach($extras as $key=>$value) { $url .= $glue.$key.'='.$value; $glue = '&'; - } + } } return $url; @@ -208,12 +216,15 @@ class grade_plugin_return { * @return string */ function get_form_fields() { - if (empty($this->type) or empty($this->plugin)) { + if (empty($this->type)) { return ''; } $result = ''; - $result .= ''; + + if (!empty($this->plugin)) { + $result .= ''; + } if (!empty($this->courseid)) { $result .= ''; @@ -234,15 +245,17 @@ class grade_plugin_return { * @return void */ function add_mform_elements(&$mform) { - if (empty($this->type) or empty($this->plugin)) { + if (empty($this->type)) { return; } $mform->addElement('hidden', 'gpr_type', $this->type); $mform->setType('gpr_type', PARAM_SAFEDIR); - $mform->addElement('hidden', 'gpr_plugin', $this->plugin); - $mform->setType('gpr_plugin', PARAM_SAFEDIR); + if (!empty($this->plugin)) { + $mform->addElement('hidden', 'gpr_plugin', $this->plugin); + $mform->setType('gpr_plugin', PARAM_SAFEDIR); + } if (!empty($this->courseid)) { $mform->addElement('hidden', 'gpr_courseid', $this->courseid); @@ -266,7 +279,7 @@ class grade_plugin_return { * @return string $url with erturn tracking params */ function add_url_params($url) { - if (empty($this->type) or empty($this->plugin)) { + if (empty($this->type)) { return $url; } @@ -276,7 +289,9 @@ class grade_plugin_return { $url .= '&gpr_type='.$this->type; } - $url .= '&gpr_plugin='.$this->plugin; + if (!empty($this->plugin)) { + $url .= '&gpr_plugin='.$this->plugin; + } if (!empty($this->courseid)) { $url .= '&gpr_courseid='.$this->courseid; @@ -293,4 +308,324 @@ class grade_plugin_return { return $url; } } + + +/** + * This class represents a complete tree of categories, grade_items and final grades, + * organises as an array primarily, but which can also be converted to other formats. + * It has simple method calls with complex implementations, allowing for easy insertion, + * deletion and moving of items and categories within the tree. + */ +class grade_tree { + + /** + * The basic representation of the tree as a hierarchical, 3-tiered array. + * @var object $top_element + */ + var $top_element; + + /** + * A string of GET URL variables, namely courseid and sesskey, used in most URLs built by this class. + * @var string $commonvars + */ + var $commonvars; + + /** + * 2D array of grade items and categories + */ + var $levels; + + /** + * Constructor, retrieves and stores a hierarchical array of all grade_category and grade_item + * objects for the given courseid. Full objects are instantiated. + * and renumbering. + * @param int $courseid + * @param boolean $fillers include fillers and colspans, make the levels var "rectangular" + * @param boolean $category_grade_last category grade item is the last child + * @param boolean $aggregation_view Either full view (0) or compact view (1) + */ + function grade_tree($courseid, $fillers=true, $category_grade_last=false, + $aggregation_view=GRADE_REPORT_AGGREGATION_VIEW_FULL) { + global $USER, $CFG; + + $this->courseid = $courseid; + $this->commonvars = "&sesskey=$USER->sesskey&id=$this->courseid"; + $this->levels = array(); + + // get course grade tree + $this->top_element = grade_category::fetch_course_tree($courseid, true); + + if ($category_grade_last) { + grade_tree::category_grade_last($this->top_element); + } + + if ($fillers) { + // inject fake categories == fillers + grade_tree::inject_fillers($this->top_element, 0); + // add colspans to categories and fillers + grade_tree::inject_colspans($this->top_element); + } + + grade_tree::fill_levels($this->levels, $this->top_element, 0); + } + + + /** + * Static recursive helper - makes the grade_item for category the last children + * @static + * @param array $element The seed of the recursion + * @return void + */ + function category_grade_last(&$element) { + if (empty($element['children'])) { + return; + } + if (count($element['children']) < 2) { + return; + } + $category_item = reset($element['children']); + $order = key($element['children']); + unset($element['children'][$order]); + $element['children'][$order] =& $category_item; + foreach ($element['children'] as $sortorder=>$child) { + grade_tree::category_grade_last($element['children'][$sortorder]); + } + } + + /** + * Static recursive helper - fills the levels array, useful when accessing tree elements of one level + * @static + * @param int $levels + * @param array $element The seed of the recursion + * @param int $depth + * @return void + */ + function fill_levels(&$levels, &$element, $depth) { + if (!array_key_exists($depth, $levels)) { + $levels[$depth] = array(); + } + + // prepare unique identifier + if ($element['type'] == 'category') { + $element['eid'] = 'c'.$element['object']->id; + } else if (in_array($element['type'], array('item', 'courseitem', 'categoryitem'))) { + $element['eid'] = 'i'.$element['object']->id; + } + + $levels[$depth][] =& $element; + $depth++; + if (empty($element['children'])) { + return; + } + $prev = 0; + foreach ($element['children'] as $sortorder=>$child) { + grade_tree::fill_levels($levels, $element['children'][$sortorder], $depth); + $element['children'][$sortorder]['prev'] = $prev; + $element['children'][$sortorder]['next'] = 0; + if ($prev) { + $element['children'][$prev]['next'] = $sortorder; + } + $prev = $sortorder; + } + } + + /** + * Static recursive helper - makes full tree (all leafes are at the same level) + */ + function inject_fillers(&$element, $depth) { + $depth++; + + if (empty($element['children'])) { + return $depth; + } + $chdepths = array(); + $chids = array_keys($element['children']); + $last_child = end($chids); + $first_child = reset($chids); + + foreach ($chids as $chid) { + $chdepths[$chid] = grade_tree::inject_fillers($element['children'][$chid], $depth); + } + arsort($chdepths); + + $maxdepth = reset($chdepths); + foreach ($chdepths as $chid=>$chd) { + if ($chd == $maxdepth) { + continue; + } + for ($i=0; $i < $maxdepth-$chd; $i++) { + if ($chid == $first_child) { + $type = 'fillerfirst'; + } else if ($chid == $last_child) { + $type = 'fillerlast'; + } else { + $type = 'filler'; + } + $oldchild =& $element['children'][$chid]; + $element['children'][$chid] = array('object'=>'filler', 'type'=>$type, 'eid'=>'', 'depth'=>$element['object']->depth,'children'=>array($oldchild)); + } + } + + return $maxdepth; + } + + /** + * Static recursive helper - add colspan information into categories + */ + function inject_colspans(&$element) { + if (empty($element['children'])) { + return 1; + } + $count = 0; + foreach ($element['children'] as $key=>$child) { + $count += grade_tree::inject_colspans($element['children'][$key]); + } + $element['colspan'] = $count; + return $count; + } + + /** + * Parses the array in search of a given eid and returns a element object with + * information about the element it has found. + * @param int $eid + * @return object element + */ + function locate_element($eid) { + if (strpos($eid, 'g') === 0) { + // it is a grade construct a new object + $id = (int)substr($eid, 1); + if (!$grade = grade_grade::fetch(array('id'=>$id))) { + return null; + } + //extra security check - the grade item must be in this tree + if (!$item_el = $this->locate_element('i'.$grade->itemid)) { + return null; + } + $grade->grade_item =& $item_el['object']; // this may speedup grade_grade methods! + return array('eid'=>'g'.$id,'object'=>$grade, 'type'=>'grade'); + } + + // it is a category or item + foreach ($this->levels as $row) { + foreach ($row as $element) { + if ($element['type'] == 'filler') { + continue; + } + if ($element['eid'] == $eid) { + return $element; + } + } + } + + return null; + } + + /** + * Return edit icon for give element + * @param object $element + * @return string + */ + function get_edit_icon($element, $gpr) { + global $CFG; + + $context = get_context_instance(CONTEXT_COURSE, $this->courseid); + if (!has_capability('moodle/grade:manage', $context)) { + return ''; + } + + $object = $element['object']; + + switch ($element['type']) { + case 'item': + case 'categoryitem': + case 'courseitem': + $url = $CFG->wwwroot.'/grade/edit/item.php?courseid='.$this->courseid.'&id='.$object->id; + $url = $gpr->add_url_params($url); + break; + + case 'category': + $url = $CFG->wwwroot.'/grade/edit/category.php?courseid='.$this->courseid.'&id='.$object->id; + $url = $gpr->add_url_params($url); + break; + + case 'grade': + //TODO: improve dealing with new grades + $url = $CFG->wwwroot.'/grade/edit/grade.php?courseid='.$this->courseid.'&id='.$object->id; + $url = $gpr->add_url_params($url); + break; + + default: + $url = null; + } + + if ($url) { + $stredit = get_string('edit'); + return ''.$stredit.''; + + } else { + return ''; + } + } + + /** + * Return hiding icon for give element + * @param object $element + * @return string + */ + function get_hiding_icon($element, $gpr) { + global $CFG; + + $context = get_context_instance(CONTEXT_COURSE, $this->courseid); + if (!has_capability('moodle/grade:manage', $context) and !has_capability('moodle/grade:hide', $context)) { + return ''; + } + + if ($element['object']->is_hidden()) { + $strshow = get_string('show'); + $url = $CFG->wwwroot.'/grade/edit/action.php?id='.$this->courseid.'&action=show&sesskey='.sesskey().'&eid='.$element['eid']; + $url = $gpr->add_url_params($url); + $action = ''.$strshow.''; + + } else { + $strhide = get_string('hide'); + $url = $CFG->wwwroot.'/grade/edit/action.php?id='.$this->courseid.'&action=hide&sesskey='.sesskey().'&eid='.$element['eid']; + $url = $gpr->add_url_params($url); + $action = ''.$strhide.''; + } + return $action; + } + + /** + * Return locking icon for give element + * @param object $element + * @return string + */ + function get_locking_icon($element, $gpr) { + global $CFG; + + $context = get_context_instance(CONTEXT_COURSE, $this->courseid); + + if ($element['object']->is_locked()) { + if (!has_capability('moodle/grade:manage', $context) and !has_capability('moodle/grade:unlock', $context)) { + return ''; + } + $strunlock = get_string('unlock', 'grades'); + $url = $CFG->wwwroot.'/grade/edit/action.php?id='.$this->courseid.'&action=unlock&sesskey='.sesskey().'&eid='.$element['eid']; + $url = $gpr->add_url_params($url); + $action = ''.$strunlock.''; + + } else { + if (!has_capability('moodle/grade:manage', $context) and !has_capability('moodle/grade:lock', $context)) { + return ''; + } + $strlock = get_string('lock', 'grades'); + $url = $CFG->wwwroot.'/grade/edit/action.php?id='.$this->courseid.'&action=lock&sesskey='.sesskey().'&eid='.$element['eid']; + $url = $gpr->add_url_params($url); + $action = ''.$strlock.''; + } + return $action; + } + +} + ?> diff --git a/grade/report/grader/index.php b/grade/report/grader/index.php index 43e5d3e1d1b..3c385bf20b4 100644 --- a/grade/report/grader/index.php +++ b/grade/report/grader/index.php @@ -127,7 +127,7 @@ $numusers = $report->get_numusers(); $report->load_final_grades(); /// Print header -print_header_simple($strgrades.':'.$reportname, ':'.$strgrades, $navigation, +print_header_simple($strgrades.': '.$reportname, ': '.$strgrades, $navigation, '', '', true, $buttons, navmenu($course)); /// Print the plugin selector at the top diff --git a/grade/report/index.php b/grade/report/index.php index c9fc53bb6b8..c53d4f9f3ec 100644 --- a/grade/report/index.php +++ b/grade/report/index.php @@ -66,7 +66,7 @@ if (empty($last)) { } else if (in_array('user', $reports)) { $last = 'user'; - + } else { $last = reset($reports); } diff --git a/grade/report/user/index.php b/grade/report/user/index.php index 3b3f2e85b39..859de8a89e1 100644 --- a/grade/report/user/index.php +++ b/grade/report/user/index.php @@ -53,7 +53,7 @@ if (has_capability('moodle/grade:viewall', $context)) { } else if (has_capability('moodle/grade:view', $usercontext) and $course->showgrades) { // ok - can view grades of this user- parent most probably - + } else { $acces = false; } @@ -77,7 +77,7 @@ $navigation = build_navigation($navlinks); /// Print header -print_header_simple($strgrades.':'.$reportname, ':'.$strgrades, $navigation, +print_header_simple($strgrades.': '.$reportname, ': '.$strgrades, $navigation, '', '', true, '', navmenu($course)); /// Print the plugin selector at the top @@ -90,13 +90,13 @@ if ($access) { // Create a report instance $report = new grade_report_user($courseid, $gpr, $context, $userid); - + $gradetotal = 0; $gradesum = 0; - + // print the page print_heading(get_string('modulename', 'gradereport_user'). ' - '.fullname($report->user)); - + if ($report->fill_table()) { echo $report->print_table(true); } diff --git a/lib/grade/grade_tree.php b/lib/grade/grade_tree.php deleted file mode 100644 index bbcb8e8fec4..00000000000 --- a/lib/grade/grade_tree.php +++ /dev/null @@ -1,238 +0,0 @@ -libdir . '/gradelib.php'; - -/** - * This class represents a complete tree of categories, grade_items and final grades, - * organises as an array primarily, but which can also be converted to other formats. - * It has simple method calls with complex implementations, allowing for easy insertion, - * deletion and moving of items and categories within the tree. - */ -class grade_tree { - - /** - * The basic representation of the tree as a hierarchical, 3-tiered array. - * @var object $top_element - */ - var $top_element; - - /** - * A string of GET URL variables, namely courseid and sesskey, used in most URLs built by this class. - * @var string $commonvars - */ - var $commonvars; - - /** - * 2D array of grade items and categories - */ - var $levels; - - /** - * Constructor, retrieves and stores a hierarchical array of all grade_category and grade_item - * objects for the given courseid. Full objects are instantiated. - * and renumbering. - * @param int $courseid - * @param boolean $fillers include fillers and colspans, make the levels var "rectangular" - * @param boolean $category_grade_last category grade item is the last child - * @param boolean $aggregation_view Either full view (0) or compact view (1) - */ - function grade_tree($courseid, $fillers=true, $category_grade_last=false, - $aggregation_view=GRADE_REPORT_AGGREGATION_VIEW_FULL) { - global $USER; - - $this->courseid = $courseid; - $this->commonvars = "&sesskey=$USER->sesskey&id=$this->courseid"; - $this->levels = array(); - - // get course grade tree - $this->top_element = grade_category::fetch_course_tree($courseid, true); - - if ($category_grade_last) { - grade_tree::category_grade_last($this->top_element); - } - - if ($fillers) { - // inject fake categories == fillers - grade_tree::inject_fillers($this->top_element, 0); - // add colspans to categories and fillers - grade_tree::inject_colspans($this->top_element); - } - - grade_tree::fill_levels($this->levels, $this->top_element, 0); - } - - - /** - * Static recursive helper - makes the grade_item for category the last children - * @static - * @param array $element The seed of the recursion - * @return void - */ - function category_grade_last(&$element) { - if (empty($element['children'])) { - return; - } - if (count($element['children']) < 2) { - return; - } - $category_item = reset($element['children']); - $order = key($element['children']); - unset($element['children'][$order]); - $element['children'][$order] =& $category_item; - foreach ($element['children'] as $sortorder=>$child) { - grade_tree::category_grade_last($element['children'][$sortorder]); - } - } - - /** - * Static recursive helper - fills the levels array, useful when accessing tree elements of one level - * @static - * @param int $levels - * @param array $element The seed of the recursion - * @param int $depth - * @return void - */ - function fill_levels(&$levels, &$element, $depth) { - if (!array_key_exists($depth, $levels)) { - $levels[$depth] = array(); - } - - // prepare unique identifier - if ($element['type'] == 'category') { - $element['eid'] = 'c'.$element['object']->id; - } else if (in_array($element['type'], array('item', 'courseitem', 'categoryitem'))) { - $element['eid'] = 'i'.$element['object']->id; - } - - $levels[$depth][] =& $element; - $depth++; - if (empty($element['children'])) { - return; - } - $prev = 0; - foreach ($element['children'] as $sortorder=>$child) { - grade_tree::fill_levels($levels, $element['children'][$sortorder], $depth); - $element['children'][$sortorder]['prev'] = $prev; - $element['children'][$sortorder]['next'] = 0; - if ($prev) { - $element['children'][$prev]['next'] = $sortorder; - } - $prev = $sortorder; - } - } - - /** - * Static recursive helper - makes full tree (all leafes are at the same level) - */ - function inject_fillers(&$element, $depth) { - $depth++; - - if (empty($element['children'])) { - return $depth; - } - $chdepths = array(); - $chids = array_keys($element['children']); - $last_child = end($chids); - $first_child = reset($chids); - - foreach ($chids as $chid) { - $chdepths[$chid] = grade_tree::inject_fillers($element['children'][$chid], $depth); - } - arsort($chdepths); - - $maxdepth = reset($chdepths); - foreach ($chdepths as $chid=>$chd) { - if ($chd == $maxdepth) { - continue; - } - for ($i=0; $i < $maxdepth-$chd; $i++) { - if ($chid == $first_child) { - $type = 'fillerfirst'; - } else if ($chid == $last_child) { - $type = 'fillerlast'; - } else { - $type = 'filler'; - } - $oldchild =& $element['children'][$chid]; - $element['children'][$chid] = array('object'=>'filler', 'type'=>$type, 'eid'=>'', 'depth'=>$element['object']->depth,'children'=>array($oldchild)); - } - } - - return $maxdepth; - } - - /** - * Static recursive helper - add colspan information into categories - */ - function inject_colspans(&$element) { - if (empty($element['children'])) { - return 1; - } - $count = 0; - foreach ($element['children'] as $key=>$child) { - $count += grade_tree::inject_colspans($element['children'][$key]); - } - $element['colspan'] = $count; - return $count; - } - - /** - * Parses the array in search of a given eid and returns a element object with - * information about the element it has found. - * @param int $eid - * @return object element - */ - function locate_element($eid) { - if (strpos($eid, 'g') === 0) { - // it is a grade construct a new object - $id = (int)substr($eid, 1); - if (!$grade = grade_grade::fetch(array('id'=>$id))) { - return null; - } - //extra security check - the grade item must be in this tree - if (!$item_el = $this->locate_element('i'.$grade->itemid)) { - return null; - } - $grade->grade_item =& $item_el['object']; // this may speedup grade_grade methods! - return array('eid'=>'g'.$id,'object'=>$grade, 'type'=>'grade'); - } - - // it is a category or item - foreach ($this->levels as $row) { - foreach ($row as $element) { - if ($element['type'] == 'filler') { - continue; - } - if ($element['eid'] == $eid) { - return $element; - } - } - } - - return null; - } - -} diff --git a/lib/grade/simpletest/testgradetree.php b/lib/grade/simpletest/testgradetree.php deleted file mode 100644 index 1e425927b39..00000000000 --- a/lib/grade/simpletest/testgradetree.php +++ /dev/null @@ -1,50 +0,0 @@ -libdir.'/simpletest/fixtures/gradetest.php'); - -class grade_tree_test extends grade_test { - - function test_grade_tree_locate_element() { - //TODO: add test - } - - function test_grade_tree_constructor() { - $tree = new grade_tree($this->courseid); - - } -} diff --git a/lib/gradelib.php b/lib/gradelib.php index 7f47530a0a5..210415f9df1 100644 --- a/lib/gradelib.php +++ b/lib/gradelib.php @@ -91,7 +91,6 @@ require_once($CFG->libdir . '/grade/grade_grade.php'); require_once($CFG->libdir . '/grade/grade_scale.php'); require_once($CFG->libdir . '/grade/grade_outcome.php'); require_once($CFG->libdir . '/grade/grade_grade_text.php'); -require_once($CFG->libdir . '/grade/grade_tree.php'); /***** PUBLIC GRADE API *****/