* Sets this category as the parent for the given children.
* A number of constraints are necessary:
* - The children must all be of the same type and at the same level
- * - The children must be consecutive (no gap between them), this assumes they have been correctly ordered previously
* - The children cannot already be top categories
* - The children cannot already have a top category
* @param array $children An array of fully instantiated grade_category OR grade_item objects
// Check type and sortorder of first child
$first_child = current($children);
$first_child_type = get_class($first_child);
- $first_child_sortorder = $first_child->get_sortorder();
foreach ($children as $child) {
if (get_class($child) != $first_child_type) {
debugging("Violated constraint: Attempted to set a category as a parent over children of 2 different types.");
return false;
}
- if ($child->get_sortorder() != $first_child_sortorder++) {
- debugging("Violated constraint: Attempted to set a category as a parent over children which were not consecutively arranged (gaps exist).");
- return false;
- }
if (grade_tree::get_element_type($child) == 'topcat') {
debugging("Violated constraint: Attempted to set a category over children which are already top categories.");
return false;
return false;
}
- $this->need_delete[] = $element->element['object'];
+ $this->need_delete[$element->element['object']->id] = $element->element['object'];
return true;
} else {
return false;
}
- $this->need_insert[] = $new_element;
+ $this->need_insert[$new_element->element['object']->id] = $new_element->element['object'];
return true;
}
/**
* One at a time, re-assigns new sort orders for every element in the tree, starting
* with a base number.
- * @return boolean;
+ * @return array A debugging array which shows the progression of variables throughout this method. This is very useful
+ * to identify problems and implement new functionality.
*/
function renumber($starting_sortorder=NULL) {
$sortorder = $starting_sortorder;
}
$newtree = array();
+ $topcatsortorder = 0;
+ $debug = array();
foreach ($this->tree_array as $topcat) {
$sortorder++;
+ $subcatsortorder = 0;
+
+ $debug[] = array('sortorder' => $sortorder,
+ 'need_update' => $this->need_update,
+ 'line' => __LINE__);
+
if (!empty($topcat['children'])) {
$topcatsortorder = $sortorder;
+ $debug[] = array('sortorder' => $sortorder,
+ 'topcatsortorder' => $topcatsortorder,
+ 'need_update' => $this->need_update,
+ 'line' => __LINE__);
+
foreach ($topcat['children'] as $subcat) {
$sortorder++;
+ $debug[] = array('sortorder' => $sortorder,
+ 'topcatsortorder' => $topcatsortorder,
+ 'need_update' => $this->need_update,
+ 'line' => __LINE__);
+
if (!empty($subcat['children'])) {
$subcatsortorder = $sortorder;
+
+ $debug[] = array('sortorder' => $sortorder,
+ 'topcatsortorder' => $topcatsortorder,
+ 'subcatsortorder' => $subcatsortorder,
+ 'need_update' => $this->need_update,
+ 'line' => __LINE__);
+
foreach ($subcat['children'] as $item) {
$sortorder++;
+
+ $debug[] = array('sortorder' => $sortorder,
+ 'topcatsortorder' => $topcatsortorder,
+ 'subcatsortorder' => $subcatsortorder,
+ 'need_update' => $this->need_update,
+ 'line' => __LINE__);
+
$newtree[$topcatsortorder]['children'][$subcatsortorder]['children'][$sortorder] = $item;
+
if ($sortorder != $item['object']->sortorder) {
- $this->need_update[$item['object']->sortorder] = $sortorder;
+ $this->need_update[$item['object']->id] = array('old_sortorder' => $item['object']->sortorder, 'new_sortorder' => $sortorder);
+ $debug[] = array('sortorder' => $sortorder,
+ 'topcatsortorder' => $topcatsortorder,
+ 'subcatsortorder' => $subcatsortorder,
+ 'need_update' => $this->need_update,
+ 'line' => __LINE__);
+
}
}
$newtree[$topcatsortorder]['children'][$subcatsortorder]['object'] = $subcat['object'];
+ $newsortorder = $subcatsortorder;
} else {
$newtree[$topcatsortorder]['children'][$sortorder] = $subcat;
+ $newsortorder = $sortorder;
}
-
- if ($sortorder != $subcat['object']->sortorder) {
- $this->need_update[$subcat['object']->sortorder] = $sortorder;
+
+ if ($newsortorder != $subcat['object']->sortorder) {
+ $this->need_update[$subcat['object']->id] = array('old_sortorder' => $subcat['object']->sortorder, 'new_sortorder' => $newsortorder);
+ $debug[] = array('sortorder' => $sortorder,
+ 'topcatsortorder' => $topcatsortorder,
+ 'subcatsortorder' => $subcatsortorder,
+ 'need_update' => $this->need_update,
+ 'line' => __LINE__);
+
}
}
$newtree[$topcatsortorder]['object'] = $topcat['object'];
+ $newsortorder = $topcatsortorder;
} else {
- $newtree[$sortorder] = $topcat;
+ $newsortorder = $sortorder;
+ $newtree[$sortorder] = $topcat;
}
-
- if ($sortorder != $topcat['object']->sortorder) {
- $this->need_update[$topcat['object']->sortorder] = $sortorder;
+
+ if ($newsortorder != $topcat['object']->sortorder) {
+ $this->need_update[$topcat['object']->id] = array('old_sortorder' => $topcat['object']->sortorder, 'new_sortorder' => $newsortorder);
+ $debug[] = array('sortorder' => $sortorder,
+ 'topcatsortorder' => $topcatsortorder,
+ 'subcatsortorder' => $subcatsortorder,
+ 'need_update' => $this->need_update,
+ 'line' => __LINE__);
+
}
}
+
$this->tree_array = $newtree;
unset($this->first_sortorder);
$this->build_tree_filled();
- return true;
+ return $debug;
}
/**
return true;
}
+
+ /**
+ * Performs any delete, insert or update queries required, depending on the objects
+ * stored in $this->need_update, need_insert and need_delete.
+ * @return boolean Success or Failure
+ */
+ function update_db() {
+ // Perform deletions first
+ foreach ($this->need_delete as $id => $object) {
+ // If an item is both in the delete AND insert arrays, it must be an existing object that only needs updating, so ignore it.
+ if (empty($this->need_insert[$id])) {
+ if (!$object->delete()) {
+ debugging("Could not delete object from DB.");
+ }
+ }
+ }
+
+ foreach ($this->need_insert as $id => $object) {
+ if (empty($this->need_delete[$id])) {
+ if (!$object->insert()) {
+ debugging("Could not insert object into DB.");
+ }
+ }
+ }
+
+ $this->need_delete = array();
+ $this->need_insert = array();
+
+ foreach ($this->need_update as $id => $sortorders) {
+ if (!set_field('grade_items', 'sortorder', $sortorders['new_sortorder'], 'id', $id)) {
+ debugging("Could not update the grade_item's sortorder in DB.");
+ }
+ }
+
+ $this->need_update = array();
+ }
}
$aggregated_grades = $category->aggregate_grades($grade_sets);
$this->assertEqual(200, count($aggregated_grades));
- $this->assertWithinMargin($aggregated_grades[rand(0, count($aggregated_grades))]->gradevalue, 0, 100);
- $this->assertWithinMargin($aggregated_grades[rand(0, count($aggregated_grades))]->gradevalue, 0, 100);
- $this->assertWithinMargin($aggregated_grades[rand(0, count($aggregated_grades))]->gradevalue, 0, 100);
- $this->assertWithinMargin($aggregated_grades[rand(0, count($aggregated_grades))]->gradevalue, 0, 100);
+ $this->assertWithinMargin($aggregated_grades[rand(1, count($aggregated_grades) - 1)]->gradevalue, 0, 100);
+ $this->assertWithinMargin($aggregated_grades[rand(1, count($aggregated_grades) - 1)]->gradevalue, 0, 100);
+ $this->assertWithinMargin($aggregated_grades[rand(1, count($aggregated_grades) - 1)]->gradevalue, 0, 100);
+ $this->assertWithinMargin($aggregated_grades[rand(1, count($aggregated_grades) - 1)]->gradevalue, 0, 100);
}
function generate_random_raw_grade($item, $userid) {
global $CFG;
$debuglevel = $CFG->debug;
- // There are 4 constraints which, if violated, should return false and trigger a debugging message. Test each of them
+ // There are 3 constraints which, if violated, should return false and trigger a debugging message. Test each of them
$grade_category = new grade_category();
$grade_category->fullname = 'new topcategory';
$grade_category->courseid = $this->courseid;
$this->assertFalse($grade_category->set_as_parent(array($child1, $child2)));
$CFG->debug = $debuglevel;
- // 2. Non-consecutive children
- $child1 = new grade_item();
- $child2 = new grade_item();
- $child1->sortorder = 1;
- $child2->sortorder = 3;
- $CFG->debug = 2;
- $this->assertFalse($grade_category->set_as_parent(array($child1, $child2)));
- $CFG->debug = $debuglevel;
-
- // 3. Child is a top category
+ // 2. Child is a top category
$child1 = new grade_category($this->grade_categories[0]);
$CFG->debug = 2;
$this->assertFalse($grade_category->set_as_parent(array($child1)));
$CFG->debug = $debuglevel;
- // 4. Child already has a top category
+ // 3. Child already has a top category
$child1 = new grade_item($this->grade_items[0]);
$CFG->debug = 2;
$this->assertFalse($grade_category->set_as_parent(array($child1)));
$this->assertFalse(empty($tree->tree_array[8]['children'][1]));
$this->assertEqual('unittestgradeitem2', $tree->tree_array[8]['children'][1]['object']->itemname);
$tree->renumber();
+
+ // Check need_? fields
+ $this->assertFalse(empty($tree->need_update));
+ $this->assertFalse(empty($tree->need_insert));
+ $this->assertFalse(empty($tree->need_delete));
+ $this->assertEqual(6, count($tree->need_update));
+ $this->assertEqual(1, count($tree->need_delete));
+ $this->assertEqual(1, count($tree->need_insert));
+ $this->assertEqual($this->grade_items[1]->itemname, $tree->need_delete[$this->grade_items[1]->id]->itemname);
+ $this->assertEqual($this->grade_items[1]->itemname, $tree->need_insert[$this->grade_items[1]->id]->itemname);
+
$this->assertFalse(empty($tree->tree_array[1]['children'][4]['children'][5]));
$this->assertEqual('unittestgradeitem3', $tree->tree_array[1]['children'][4]['children'][5]['object']->itemname);
$tree1 = $tree;
$tree->renumber();
$this->assertEqual($tree1->tree_array[1]['object'], $tree->tree_array[1]['object']);
+ $this->assertTrue(empty($tree->need_update));
}
function test_grade_tree_remove_element() {
function test_grade_tree_build_tree_filled() {
$tree = new grade_tree($this->courseid);
- echo $tree->display_grades() . "<br />";
$element = $tree->tree_array[7];
$tree->remove_element(7);
$tree->renumber();
- echo $tree->display_grades() . "<br />";
$tree->insert_element($element, 4);
$tree->renumber();
- echo $tree->display_grades() . "<br />";
}
+
+ function test_grade_tree_update_db() {
+ $tree = new grade_tree($this->courseid);
+ $tree->remove_element(7);
+ $tree->renumber();
+ $tree->update_db();
+ $item = grade_item::fetch('id', $this->grade_items[6]->id);
+ $this->assertTrue(empty($item->id));
+
+ $tree->move_element(4, 9);
+ $tree->renumber();
+ $tree->update_db();
+ $item = grade_item::fetch('id', $this->grade_items[1]->id);
+ $this->assertFalse(empty($item->id));
+ $this->assertEqual(8, $item->sortorder);
+
+ $grade_item = new grade_item($this->grade_items[2]);
+ $element = array('object' => $grade_item);
+ $tree->insert_element($element, 9);
+
+ }
}