I wrote class to manage with category tree as easy as possible. This method is based on idea presented here (only Polish version, unfortunately). Script is using PostgreSQL and I tried to make it works on MySQL4.1 using PHP. I have problems with two things: getTree (draw whole Tree) and "ordering nodes", maybe you could give me any clues how to implement it.
What you can do with this class so far?
+ add parents and children
+ edit names
+ get Id/Name of a node by name/id
+ get node level
+ getPath to node
+ delete nod (together with its children if any)

Class is using PDO.

PHP Code:
class Tree
{
    private 
$db                        false;
    private 
$dbTreeTable            "kategorie";        
    private 
$dbTreeBindingsTable    "powiazania";

    public function 
__construct($db=null){
        if(!
is_null($db)){
            
$this->db $db;
        }

        if(
$this->db === false){
            die(
"brak polaczenia z db");
        }
    }

    public function 
createParentNode($sName){
        if(!empty(
$sName) && is_string($sName) && $this->getNodeIdByName($sName) === false){
            try{
                
$this->db->beginTransaction();
                
$this->db->exec("INSERT INTO $this->dbTreeTable (name) VALUES ('$sName')");
                
$this->db->exec("INSERT INTO $this->dbTreeBindingsTable (parent_id, child_id, depth) VALUES (LAST_INSERT_ID(), LAST_INSERT_ID(), 0)");
                
$this->db->commit();
                return 
true;
            }
            catch (
Exception $e) {
                
$this->db->rollBack();
                echo 
"Failed: " $e->getMessage();
                return 
false;
            }
        }
        else{
            echo 
'Błąd nazwy rodzica lub taki rodzic już istnieje!';
            return 
false;
        }
    }

    public function 
createChildNode($id,$sName){
        if(!empty(
$id)){
            
$iId = (is_string($id)) ? $this->getNodeIdByName($id) : (int)$id;
            unset(
$id);
            if(
$iId){
                if(!empty(
$sName) && is_string($sName) && $this->isParentChild($iId,$sName) === false){
                    try{
                        
$this->db->beginTransaction();
                        
$this->db->exec("INSERT INTO $this->dbTreeTable (name) VALUES ('$sName')");
                        
$this->db->exec("INSERT INTO $this->dbTreeBindingsTable (parent_id, child_id, depth) VALUES (LAST_INSERT_ID(), LAST_INSERT_ID(), 0)");
                        
$this->db->exec("INSERT INTO $this->dbTreeBindingsTable (parent_id, child_id, depth) SELECT parent_id, LAST_INSERT_ID(), depth+1 FROM $this->dbTreeBindingsTable WHERE child_id = $iId");
                        
$this->db->commit();
                        return 
true;
                    }
                    catch (
Exception $e) {
                        
$this->db->rollBack();
                        echo 
"Failed: " $e->getMessage();
                        return 
false;
                    }
                }
                else{
                    echo 
'Bład nazwy dziecka!';
                    return 
false;
                }
            }
            else{
                echo 
'Błąd id rodzica!';
                return 
false;
            }
        }
        return 
false;
    }

    public function 
getNodeNameById($iId){
        if(!empty(
$iId) && is_numeric($iId)){
            
$stmt $this->db->prepare("SELECT name FROM $this->dbTreeTable WHERE id = ? LIMIT 1");
            
$stmt->execute(array($iId));
            unset(
$iId);
            if(
$result $stmt->fetch(PDO::FETCH_NUM)){
                
$stmt->closeCursor();
                unset(
$stmt);
                return (string)
$result[0];
            }
        }
        return 
false;
    }

    public function 
getNodeIdByName($sName){
        if(!empty(
$sName) && is_string($sName)){
            
$stmt $this->db->prepare("SELECT id FROM $this->dbTreeTable WHERE name = ? LIMIT 1");
            
$stmt->execute(array($sName));
            unset(
$sName);
            if(
$result $stmt->fetch(PDO::FETCH_NUM)){
                
$stmt->closeCursor();
                unset(
$stmt);
                return (int)
$result[0];
            }
        }
        return 
false;
    }

    public function 
getNodeLevel($id){
        if(!empty(
$id)){
            
$iId = (is_string($id)) ? $this->getNodeIdByName($id) : (int)$id;
            unset(
$id);
            if(
$iId){
                
$stmt $this->db->prepare("SELECT depth FROM $this->dbTreeBindingsTable WHERE child_id = ? ORDER BY depth DESC LIMIT 1");
                
$stmt->execute(array($iId));            
                if(
$result $stmt->fetch(PDO::FETCH_NUM)){
                    
$stmt->closeCursor();
                    unset(
$iId,$stmt);
                    return (int)
$result[0];
                }
            }
        }
        return 
false;
    }

    public function 
getParents(){
        
$stmt $this->db->prepare("SELECT c.id, c.name FROM $this->dbTreeTable c WHERE NOT exists (SELECT * FROM $this->dbTreeBindingsTable b WHERE c.id = b.child_id AND b.depth = 1)");
        if(
$stmt->execute()){
            
$a = array();
            while(
$row $stmt->fetch(PDO::FETCH_NUM)){
                
array_push($a,array('id'    => $row[0],
                                    
'name'    => $row[1]));         
            }
            
$stmt->closeCursor();
            return 
$a;
        }
        return 
false;
    }

    public function 
getParentChildren($id){
        if(!empty(
$id)){
            
$iId = (is_string($id)) ? $this->getNodeIdByName($id) : (int)$id;
            unset(
$id);
            if(
$iId){
                
$stmt $this->db->prepare("SELECT c.id, c.name FROM $this->dbTreeTable c JOIN $this->dbTreeBindingsTable b ON c.id = b.child_id WHERE b.parent_id = ? AND b.depth = 1");
                if(
$stmt->execute(array($iId))){
                    
$a = array();
                    while(
$row $stmt->fetch(PDO::FETCH_NUM)){
                        
array_push($a,array('id'    => $row[0],
                                            
'name'    => $row[1]));      
                    }
                    
$stmt->closeCursor();
                    return 
$a;
                }
            }
        }
        return 
false;
    }

    public function 
isParentChild($iId$sName){
        
$a $this->getParentChildren($iId);
        if(!empty(
$sName) && is_string($sName) && is_array($a)){ 
            foreach(
$a as $val){
                if(
$val['name'] == $sName){
                    return 
true;
                }
            }
        }
        return 
false;
    }

    public function 
getPath($id){
        if(!empty(
$id)){
            
$iId = (is_string($id)) ? $this->getNodeIdByName($id) : (int)$id;
            unset(
$id);
            if(
$iId){
                
$stmt $this->db->prepare("SELECT c.id, c.name FROM $this->dbTreeTable c JOIN $this->dbTreeBindingsTable b ON c.id = b.parent_id WHERE b.child_id = ? ORDER BY b.depth DESC");
                if(
$stmt->execute(array($iId))){
                    
$a = array();
                    while(
$row $stmt->fetch(PDO::FETCH_NUM)){
                        
array_push($a,array('id'    => $row[0],
                                            
'name'    => $row[1]));      
                    }
                    
$stmt->closeCursor();
                    return 
$a;
                }
            }
        }
        return 
false;
    }

    public function 
changeNodeName($id,$sName){
        if(!empty(
$id) && !empty($sName) && is_string($sName)){
            
$iId = (is_string($id)) ? $this->getNodeIdByName($id) : (int)$id;
            unset(
$id);
            if(
$iId){
                
$sName mysql_escape_string($sName);
                try{
                    
$this->db->beginTransaction();
                    if(
$this->db->exec("UPDATE $this->dbTreeTable SET name = '$sName' WHERE id = '".$iId."'") === 1){
                        
$this->db->commit();
                        echo 
'ok';
                        return 
true;
                    }
                    else{
                        echo 
'Probowano zmienić więcej niż 1 rekord!';
                        
$this->db->rollBack();
                        return 
false;
                    }
                }
                catch (
Exception $e) {
                    
$this->db->rollBack();
                    echo 
"Failed: " $e->getMessage();
                    return 
false;
                }
            }
        }
        return 
false;
    }

    public function 
removeNode($id){
        if(!empty(
$id)){
            
$iId = (is_string($id)) ? $this->getNodeIdByName($id) : (int)$id;
            unset(
$id);
            if(
$iId){
                
$stmt $this->db->exec("CREATE TEMPORARY TABLE tmptable select * from $this->dbTreeBindingsTable where child_id IN (select child_id from $this->dbTreeBindingsTable where parent_id = $iId)");
                
$this->db->exec("DELETE c from $this->dbTreeTable as c,tmptable where c.id = tmptable.child_id");
                
$this->db->exec("DELETE b from $this->dbTreeBindingsTable as b,tmptable where b.child_id = tmptable.child_id");
                return 
true;
            }
        }
        return 
false;
    }

db:
HTML Code:
CREATE TABLE kategorie (
  id int(11) NOT NULL auto_increment,
  name varchar(255) NOT NULL default '',
  ordering int(11) NOT NULL default '0',
  PRIMARY KEY  (id)
);
CREATE TABLE powiazania (
  parent_id int(11) NOT NULL default '0',
  child_id int(11) NOT NULL default '0',
  depth int(11) NOT NULL default '0',
  KEY parent_id (parent_id),
  KEY child_id (child_id),
  KEY depth (depth)
)
Thanks in advance for any comments and advices how could I implement getTree and changing nod order.