MDL-9506 Created new grade_tree object for working with a tree of grade_categories and items.

This commit is contained in:
nicolasconnault
2007-05-16 15:04:35 +00:00
parent 91e7b2b18a
commit e835361626
3 changed files with 278 additions and 0 deletions
+236
View File
@@ -0,0 +1,236 @@
<?php // $Id$
///////////////////////////////////////////////////////////////////////////
// //
// NOTICE OF COPYRIGHT //
// //
// Moodle - Modular Object-Oriented Dynamic Learning Environment //
// http://moodle.com //
// //
// Copyright (C) 2001-2003 Martin Dougiamas http://dougiamas.com //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation; either version 2 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License for more details: //
// //
// http://www.gnu.org/copyleft/gpl.html //
// //
///////////////////////////////////////////////////////////////////////////
/**
* 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 first sortorder for this tree, before any changes were made.
* @var int $first_sortorder
*/
var $first_sortorder;
/**
* The basic representation of the tree as a hierarchical, 3-tiered array.
* @var $tree_array
*/
var $tree_array = array();
/**
* Parses the array in search of a given sort order (the elements are indexed by
* sortorder), and returns a stdClass object with vital information about the
* element it has found.
* @param int $sortorder
* @return object element
*/
function locate_element($sortorder) {
$topcatcount = 0;
foreach ($this->tree_array as $topcatkey => $topcat) {
$topcatcount++;
$subcatcount = 0;
$retval = new stdClass();
$retval->topcatindex = $topcatkey;
if ($topcatkey == $sortorder) {
$retval->depth = 1;
$retval->element = $topcat;
$retval->position = $topcatcount;
return $retval;
}
if (is_array($topcat)) {
foreach ($topcat as $subcatkey => $subcat) {
$subcatcount++;
$itemcount = 0;
$retval->subcatindex = $subcatkey;
if ($subcatkey == $sortorder) {
$retval->depth = 2;
$retval->element = $subcat;
$retval->position = $subcatcount;
return $retval;
}
if (is_array($subcat)) {
foreach ($subcat as $itemkey => $item) {
$itemcount++;
$retval->itemindex = $itemkey;
if ($itemkey == $sortorder) {
$retval->depth = 3;
$retval->element = $item;
$retval->position = $itemcount;
return $retval;
}
}
}
}
}
}
return $retval;
}
/**
* Removes the given element (a stdClass object or a sortorder), remove_elements
* it from the tree. This does not renumber the tree.
* @var object $element An stdClass object typically returned by $this->locate(), or a sortorder
* @return boolean
*/
function remove_element($element) {
if (isset($element->depth)) {
switch ($element->depth) {
case 1:
unset($this->tree_array[$element->topcatindex]);
break;
case 2:
unset($this->tree_array[$element->topcatindex][$element->subcatindex]);
break;
case 3:
unset($this->tree_array[$element->topcatindex][$element->subcatindex][$element->itemindex]);
break;
}
return true;
} else {
$element = $this->locate_element($element);
if (!empty($element)) {
return $this->remove_element($element);
} else {
return false;
}
}
}
/**
* Inserts an element in the tree. This can be either an array as returned by the grade_category methods, or
* an element object returned by grade_tree.
* @param mixed $element array or object. If object, the sub-tree is contained in $object->element
* @param int $destination_sortorder Where to insert the element
* @param string $position Either 'before' the destination_sortorder or 'after'
* @param boolean
*/
function insert_element($element, $destination_sortorder, $position='before') {
if ($position == 'before') {
$offset = -1;
} elseif ($position == 'after') {
$offset = 0;
} else {
die ('move_element(..... $position) can only be "before" or "after", you gave ' . $position);
}
// TODO Problem when moving topcategories: sortorder gets reindexed when splicing the array
$destination_array = array($destination_sortorder => $source->element);
switch($element->depth) {
case 1:
array_splice($this->tree_array,
$element->position + $offset, 0,
$destination_array);
break;
case 2:
array_splice($this->tree_array[$element->topcatindex],
$element->position + $offset, 0,
$destination_array);
break;
case 3:
array_splice($this->tree_array[$element->topcatindex][$element->subcatindex],
$element->position + $offset, 0,
$destination_array);
break;
}
return true;
}
/**
* Moves an existing element in the tree to another position OF EQUAL LEVEL. This
* constraint is essential and very important.
* @param int $source_sortorder The sortorder of the element to move
* @param int $destination_sortorder The sortorder where the element will go
* @param string $position Either 'before' the destination_sortorder or 'after' it
* @return boolean
*/
function move_element($source_sortorder, $destination_sortorder, $position='before') {
// Locate the position of the source element in the tree
$source = $this->locate_element($source_sortorder);
// Remove this element from the tree
$this->remove_element($source);
$destination = $this->locate_element($destination_sortorder);
if ($destination->depth != $source->depth) {
echo "Source and Destination were at different levels.";
return false;
}
// Insert the element before the destination sortorder
$this->insert_element($destination, $destination_sortorder, $position);
return true;
}
/**
* One at a time, re-assigns new sort orders for every element in the tree, starting
* with a base number.
* @return boolean;
*/
function renumber($starting_sortorder=NULL) {
$sortorder = $starting_sortorder;
if (empty($starting_sortorder)) {
$sortorder = $this->first_sortorder;
}
$newtree = array();
foreach ($this->tree_array as $topcat) {
$sortorder++;
if (is_array($topcat)) {
$topcatsortorder = $sortorder;
foreach ($topcat as $subcat) {
$sortorder++;
if(is_array($subcat)) {
$subcatsortorder = $sortorder;
foreach ($subcat as $item) {
$sortorder++;
$newtree[$topcatsortorder][$subcatsortorder][$sortorder] = $item;
}
} else {
$newtree[$topcatsortorder][$sortorder] = $subcat;
}
}
} else {
$newtree[$sortorder] = $topcat;
}
}
$this->tree_array = $newtree;
return true;
}
}
@@ -481,5 +481,8 @@ class grade_item_test extends gradelib_test {
$grade_item->load_final();
$this->assertEqual(3, count($grade_item->grade_grades_final));
}
function test_float_keys() {
}
}
?>
@@ -0,0 +1,39 @@
<?php // $Id$
///////////////////////////////////////////////////////////////////////////
// //
// NOTICE OF COPYRIGHT //
// //
// Moodle - Modular Object-Oriented Dynamic Learning Environment //
// http://moodle.org //
// //
// Copyright (C) 1999-2004 Martin Dougiamas http://dougiamas.com //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation; either version 2 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License for more details: //
// //
// http://www.gnu.org/copyleft/gpl.html //
// //
///////////////////////////////////////////////////////////////////////////
/**
* Unit tests for grade_tree object.
*
* @author [email protected]
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
* @package moodlecore
*/
require_once(dirname(__FILE__) . '/../../../../config.php');
global $CFG;
require_once($CFG->libdir . '/simpletest/testgradelib.php');
class grade_tree_test extends gradelib_test {
}