diff --git a/.project b/.project new file mode 100644 index 0000000..8c79d47 --- /dev/null +++ b/.project @@ -0,0 +1,11 @@ + + + mptt + + + + + + + + diff --git a/Formation-0.9.tar.gz b/Formation-0.9.tar.gz deleted file mode 100644 index c72bb9d..0000000 Binary files a/Formation-0.9.tar.gz and /dev/null differ diff --git a/MPTT.php b/MPTT.php index d8fb27e..467e0a7 100644 --- a/MPTT.php +++ b/MPTT.php @@ -54,7 +54,30 @@ public function __construct($id = FALSE) } - + + ////////////////////////////////////////// + // Lock functions + ////////////////////////////////////////// + + /** + * Locks tree table + * This is a straight write lock - the database blocks until the previous lock is released + */ + protected function lock_tree($aliases = array()) + { + $sql = "LOCK TABLE " . $this->table . " WRITE"; + return self::$db->query($sql); + } + + /** + * Unlocks tree table + * Releases previous lock + */ + protected function unlock_tree() + { + $sql = "UNLOCK TABLES"; + return self::$db->query($sql); + } /** * Bit of an odd function since the node is supplied @@ -366,10 +389,11 @@ function insert_as_first_child_of($parent_node) $this->$rgt_col=$parent_node->$lft_col+2; //Get scope from current object (obsolete) $this->$scp_col=$this->get_scope(); - + + $this->lock_tree(); $this->modify_node($this->$lft_col,2); $this->save_node(); - + $this->unlock_tree(); return $this; } @@ -392,9 +416,11 @@ function insert_as_last_child_of($parent_node) $this->$lft_col=$parent_node->$rgt_col; $this->$rgt_col=$parent_node->$rgt_col+1; $this->$scp_col=$this->get_scope(); - + + $this->lock_tree(); $this->modify_node($this->$lft_col,2); - $this->save_node(); + $this->save_node(); + $this->unlock_tree(); return $this; } @@ -417,9 +443,11 @@ function insert_as_prev_sibling_of($focus_node) $this->$lft_col=$focus_node->$lft_col; $this->$rgt_col=$focus_node->$lft_col+1; $this->$scp_col=$this->get_scope(); - + + $this->lock_tree(); $this->modify_node($this->$lft_col,2); - $this->save_node(); + $this->save_node(); + $this->unlock_tree(); return $this; } @@ -442,9 +470,11 @@ function insert_as_next_sibling_of($focus_node) $this->$lft_col=$focus_node->$rgt_col+1; $this->$rgt_col=$focus_node->$rgt_col+2; $this->$scp_col=$this->get_scope(); - + + $this->lock_tree(); $this->modify_node($this->$lft_col,2); - $this->save_node(); + $this->save_node(); + $this->unlock_tree(); return $this; } @@ -490,18 +520,21 @@ function delete_node($children=true) $where=$leftcol . '>='.$leftval .' AND '. $rightcol .' <= ' . $rightval . ' AND '. $this->scope_column .' = '.$this->get_scope() ; - + + $this->lock_tree(); //Delete node and children self::$db->delete($this->table, $where); //Modify other nodes to restore tree integrity - $this->modify_node($rightval+1, $leftval - $rightval - 1); + $this->modify_node($rightval+1, $leftval - $rightval - 1); + $this->unlock_tree(); } else { if($this->is_root()){ Log::add('error', 'Cannot delete root node without deleting its children' ); return false; - } + } + $this->lock_tree(); //Get children before the parent is gone //Set parent ids right again $parent_node=$this->get_node($this->$parent_column); @@ -544,7 +577,8 @@ function delete_node($children=true) $child->$parent_column=$parent_node->id; $child->save_node(); } - } + } + $this->unlock_tree(); } @@ -558,13 +592,15 @@ function delete_node($children=true) * @return */ function delete_descendants() - { + { + $this->lock_tree(); $this->get_children(); foreach($this->children as $child) { $child->delete_node(); - } + } + $this->unlock_tree(); $this->children=array(); return true; } @@ -580,7 +616,8 @@ function delete_children() { $child->delete_node(false); - } + } + $this->unlock_tree(); $this->children=array(); return true; } @@ -799,22 +836,23 @@ function is_descendant_of($control_node) */ function is_child_of($control_node) { - $child_id=$this->id; - $parent_id=$control_node->id; - - self::$db->select('count(*) as is_child'); - self::$db->from($this->table); - self::$db->where('id',$child_id); - self::$db->where($this->parent_column,$parent_id); - self::$db->where($this->scope_column, $this->get_scope()); - - $result=self::$db->get(); - - if ($row = $result->current()) { - return $row->is_child > 0; - } + $child_id=$this->id; + $parent_id=$control_node->id; + + self::$db->select('count(*) as is_child'); + self::$db->from($this->table); + self::$db->where('id',$child_id); + self::$db->where($this->parent_column,$parent_id); + self::$db->where($this->scope_column, $this->get_scope()); + + $result=self::$db->get(); + + if ($row = $result->current()) + { + return $row->is_child > 0; + } - return false; + return false; } @@ -957,35 +995,38 @@ function debug_tree($tree, $disp_col, $ind = '') * @param $parent_id Object * @param $left Object */ - function rebuild_tree($parent_id, $left) { - // the right value of this node is the left value + 1 - $right = $left+1; + function rebuild_tree($parent_id, $left) { + $this->lock_tree(); + // the right value of this node is the left value + 1 + $right = $left+1; - // get all children of this node + // get all children of this node self::$db->select('id'); self::$db->where($this->parent_column, $parent_id); self::$db->where($this->scope_column, $this->get_scope()); self::$db->from($this->table); $result=self::$db->get(); - foreach ($result as $row) { - // recursive execution of this function for each - // child of this node - // $right is the current right value, which is - // incremented by the rebuild_tree function - $right = $this->rebuild_tree($row->id, $right); - } - - // we've got the left value, and now that we've processed - // the children of this node we also know the right value + foreach ($result as $row) { + // recursive execution of this function for each + // child of this node + // $right is the current right value, which is + // incremented by the rebuild_tree function + $right = $this->rebuild_tree($row->id, $right); + } + + // we've got the left value, and now that we've processed + // the children of this node we also know the right value self::$db->set($this->left_column, $left); self::$db->set($this->right_column, $right); self::$db->where('id',$parent_id); self::$db->where($this->scope_column, $this->get_scope()); self::$db->update($this->table); - // return the right value of this node + 1 - return $right+1; + // return the right value of this node + 1 + return $right+1; + + $this->unlock_tree(); } /*