!C99Shell v. 1.0 pre-release build #13!

Software: Apache. PHP/5.5.15 

uname -a: Windows NT SVR-DMZ 6.1 build 7600 (Windows Server 2008 R2 Enterprise Edition) i586 

SYSTEM 

Safe-mode: OFF (not secure)

C:\Intranet\C\xampp\php\PEAR\DB\   drwxrwxrwx
Free 4.09 GB of 39.52 GB (10.36%)
Detected drives: [ a ] [ c ] [ d ] [ e ] [ f ]
Home    Back    Forward    UPDIR    Refresh    Search    Buffer    Encoder    Tools    Proc.    FTP brute    Sec.    SQL    PHP-code    Update    Feedback    Self remove    Logout    


Viewing file:     NestedSet.php (60.41 KB)      -rw-rw-rw-
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
<?php
//
// +----------------------------------------------------------------------+
// | PEAR :: DB_NestedSet                                                 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2003 The PHP Group                                |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.0 of the PHP license,       |
// | that is bundled with this package in the file LICENSE, and is        |
// | available at through the world-wide-web at                           |
// | http://www.php.net/license/2_02.txt.                                 |
// | If you did not receive a copy of the PHP license and are unable to   |
// | obtain it through the world-wide-web, please send a note to          |
// | license@php.net so we can mail you a copy immediately.               |
// +----------------------------------------------------------------------+
// | Authors: Daniel Khan <dk@webcluster.at>                              |
// |           Jason Rust  <jason@rustyparts.com>                          |
// +----------------------------------------------------------------------+
// $Id: NestedSet.php,v 1.31 2003/08/13 20:09:29 datenpunk Exp $
//

// CREDITS:
// --------
// - Many thanks to Jason Rust for doing great improvements and cleanup work for the current release
// - Thanks to Kristian Koehntopp for publishing an explanation of the Nested Set
//   technique and for the great work he did and does for the php community
// - Thanks to Daniel T. Gorski for his great tutorial on www.develnet.org
// - Thanks to Hans Lellelid for suggesting support for MDB and for helping me with the
//   implementation
//   ...
// - Thanks to my parents for ... just kidding :]

require_once 'PEAR.php';

// {{{ constants

// Error and message codes
define('NESE_ERROR_RECURSION',    'E100');
define('NESE_DRIVER_NOT_FOUND',   'E200');
define('NESE_ERROR_NOHANDLER',    'E300');
define('NESE_ERROR_TBLOCKED',     'E010');
define('NESE_MESSAGE_UNKNOWN',    'E0');
define('NESE_ERROR_NOTSUPPORTED''E1');
define('NESE_ERROR_PARAM_MISSING','E400');
define('NESE_ERROR_NOT_FOUND',    'E500');

// for moving a node before another
define('NESE_MOVE_BEFORE''BE');
// for moving a node after another
define('NESE_MOVE_AFTER''AF');
// for moving a node below another
define('NESE_MOVE_BELOW''SUB');

// }}}
// {{{ DB_NestedSet:: class

/**
* DB_NestedSet is a class for handling nested sets
*
* @author       Daniel Khan <dk@webcluster.at>
* @package      DB_NestedSet
* @version      $Revision: 1.31 $
* @access       public
*/

// }}}
class DB_NestedSet extends PEAR {
    
// {{{ properties
    
    /**
    * @var array The field parameters of the table with the nested set. Format: 'realFieldName' => 'fieldId'
    * @access public
    */
    
var $params = array(
    
'STRID' => 'id',
    
'ROOTID'=> 'rootid',
    
'l'     => 'l',
    
'r'     => 'r',
    
'STREH' => 'norder',
    
'LEVEL' => 'level',
    
'STRNA' => 'name'
    
);
    
    
/**
    * @var array The above parameters flipped for easy access
    * @access private
    */
    
var $flparams = array();
    
    
/**
    * @var array An array of field ids that must exist in the table
    * Not used yet
    */
    
var $requiredParams = array('id''rootid''l''r''norder''level');
    
    
/**
    * @var string The table with the actual tree data
    * @access public
    */
    
var $node_table 'tb_nodes';
    
    
/**
    * @var string The table to handle locking
    * @access public
    */
    
var $lock_table 'tb_locks';
    
    
/**
    * @var string The table used for sequences
    * @access public
    */
    
var $sequence_table;
    
    
/**
    * Secondary order field.  Normally this is the order field, but can be changed to
    * something else (i.e. the name field so that the tree can be shown alphabetically)
    * @var string
    * @access public
    */
    
var $secondarySort;
    
    
/**
    * @var int The time to live of the lock
    * @access public
    */
    
var $lockTTL 1;
    
    
/**
    * @var bool Enable debugging statements?
    * @access public
    */
    
var $debug false;
    
    
/**
    * @var bool Lock the structure of the table?
    * @access private
    */
    
var $structureTableLock false;
    
    
/**
    * @var bool Skip the callback events?
    * @access private
    */
    
var $skipCallbacks false;
    
    
/**
    * @var object cache Optional PEAR::Cache object
    * @access public
    */
    
var $cache false;
    
    
/**
    * @var bool Do we want to use caching
    * @access private
    */
    
var $_caching false;
    
    
/**
    * 
    * @var bool Temporary switch for cache
    * @access private
    */
    
var $_restcache false;
    
    
/**
    * @var array Map of error messages to their descriptions
    */
    
var $messages = array(
    
NESE_ERROR_RECURSION    => 'This operation would lead to a recursion',
    
NESE_ERROR_TBLOCKED     => 'The structure Table is locked for another database operation, please retry.',
    
NESE_DRIVER_NOT_FOUND   => 'The selected database driver wasn\'t found',
    
NESE_ERROR_NOTSUPPORTED => 'Method not supported yet',
    
NESE_ERROR_NOHANDLER    => 'Event handler not found',
    
NESE_ERROR_PARAM_MISSING=> 'Parameter missing',
    
NESE_MESSAGE_UNKNOWN    => 'Unknown error or message',
    
NESE_ERROR_NOT_FOUND    => 'Node not found'
    );
    
    
/**
    * @var array The array of event listeners
    * @access public
    */
    
var $eventListeners = array();
    
    
// }}}
    // +---------------------------------------+
    // | Base methods                          |
    // +---------------------------------------+
    // {{{ constructor 
    
    

    
    /**
    * Constructor
    *
    * @param array $params Database column fields which should be returned
    *
    * @access private
    * @return void
    */
    
function DB_NestedSet($params)
    {
        
$this->_debugMessage('DB_NestedSet()');
        
$this->PEAR();
        if (
is_array($params) && count($params) > 0) {
            
$this->params $params;
        }
        
        
$this->flparams array_flip($this->params);
        
$this->sequence_table $this->node_table '_' $this->flparams['id'];
        
$this->secondarySort $this->flparams['norder'];
    }
    
    
// }}}
    // {{{ factory
    
    /**
    * Handles the returning of a concrete instance of DB_NestedSet based on the driver.
    *
    * @param string $driver The driver, such as DB or MDB
    * @param string $dsn The dsn for connecting to the database
    * @param array $params The field name params for the node table
    *
    * @access public
    * @return object The DB_NestedSet object
    */
    
function & factory($driver$dsn$params = array())
    {
        
$driverpath dirname(__FILE__).'/NestedSet/'$driver.'.php';
        if(!
file_exists($driverpath) || !$driver) {
            return new 
PEAR_Error('E200',"The database driver '$driver' wasn't found");
        }
        
        include_once(
$driverpath);
        
$classname 'DB_NestedSet_' $driver;
        return new 
$classname($dsn$params);
    }
    
    
// }}}
    // {{{ destructor
    
    /**
    * PEAR Destructor
    * Releases all locks
    * Closes open database connections
    *
    * @access private
    * @return void
    */
    
function _DB_NestedSet()
    {
        
$this->_debugMessage('_DB_NestedSet()');
        
$this->_releaseLock();
    }
    
    
// }}}
    // +----------------------------------------------+
    // | NestedSet manipulation and query methods     |
    // |----------------------------------------------+
    // | Querying the tree                            |
    // +----------------------------------------------+
    // {{{ getAllNodes()
    
    /**
    * Fetch the whole NestedSet
    *
    * @param bool $keepAsArray (optional) Keep the result as an array or transform it into
    *             a set of DB_NestedSet_Node objects?
    * @param bool $aliasFields (optional) Should we alias the fields so they are the names
    *             of the parameter keys, or leave them as is?
    * @param array $addSQL (optional) Array of additional params to pass to the query.
    *
    * @access public
    * @return mixed False on error, or an array of nodes
    */
    
function getAllNodes($keepAsArray false$aliasFields true$addSQL = array())
    {
        
$this->_debugMessage('getAllNodes()');
        
$sql sprintf('SELECT %s %s FROM %s %s %s ORDER BY %s.%s, %s.%s ASC'
                
$this->_getSelectFields($aliasFields),
                
$this->_addSQL($addSQL'cols'),
                
$this->node_table,
                
$this->_addSQL($addSQL'join'),
                
$this->_addSQL($addSQL'append'),
                
$this->node_table,
                
$this->flparams['level'],
                
$this->node_table,
                
$this->secondarySort);
        
        if (!
$this->_caching) {
            
$nodeSet $this->_processResultSet($sql$keepAsArray$aliasFields);
        } else {
            
$nodeSet $this->cache->call('DB_NestedSet->_processResultSet'$sql$keepAsArray$aliasFields);
        }
        
        
// EVENT (nodeLoad)
        
foreach (array_keys($nodeSet) as $key) {
            
$this->triggerEvent('nodeLoad'$nodeSet[$key]);
        }
        return 
$nodeSet;
    }
    
    
// }}}
    // {{{ getRootNodes()
    
    /**
    * Fetches the first level (the rootnodes) of the NestedSet
    *
    * @param bool $keepAsArray (optional) Keep the result as an array or transform it into
    *             a set of DB_NestedSet_Node objects?
    * @param bool $aliasFields (optional) Should we alias the fields so they are the names
    *             of the parameter keys, or leave them as is?
    * @param array $addSQL (optional) Array of additional params to pass to the query.
    *
    * @see _addSQL()
    * @access public
    * @return mixed False on error, or an array of nodes
    */
    
function getRootNodes($keepAsArray false$aliasFields true$addSQL = array())
    {
        
$this->_debugMessage('getRootNodes()');
        
$sql sprintf('SELECT %s %s FROM %s %s WHERE %s.%s=%s.%s %s ORDER BY %s.%s ASC'
                
$this->_getSelectFields($aliasFields),
                
$this->_addSQL($addSQL'cols'),
                
$this->node_table,
                
$this->_addSQL($addSQL'join'),
                
$this->node_table,
                
$this->flparams['id'],
                
$this->node_table,
                
$this->flparams['rootid'],
                
$this->_addSQL($addSQL'append'),
                
$this->node_table,
                
$this->secondarySort);

        if (!
$this->_caching) {
            
$nodeSet $this->_processResultSet($sql$keepAsArray$aliasFields);
        } else {
            
$nodeSet $this->cache->call('DB_NestedSet->_processResultSet'$sql$keepAsArray$aliasFields);
        }
        
        
// EVENT (nodeLoad)
        
foreach (array_keys($nodeSet) as $key) {
            
$this->triggerEvent('nodeLoad'$nodeSet[$key]);
        }
        return 
$nodeSet;
    }
    
    
// }}}
    // {{{ getBranch()
    
    /**
    * Fetch the whole branch where a given node id is in
    *
    * @param int  $id The node ID
    * @param bool $keepAsArray (optional) Keep the result as an array or transform it into
    *             a set of DB_NestedSet_Node objects?
    * @param bool $aliasFields (optional) Should we alias the fields so they are the names
    *             of the parameter keys, or leave them as is?
    * @param array $addSQL (optional) Array of additional params to pass to the query.
    *
    * @see _addSQL()
    * @access public
    * @return mixed False on error, or an array of nodes
    */
    
function getBranch($id$keepAsArray false$aliasFields true$addSQL = array())
    {
        
$this->_debugMessage('getBranch($id)');
        if (!(
$thisnode $this->_getNodeObject($id))) {
            return 
false;
        }
        
        
$sql sprintf('SELECT %s %s FROM %s %s WHERE %s.%s=%s %s ORDER BY %s.%s, %s.%s ASC'
                
$this->_getSelectFields($aliasFields),
                
$this->_addSQL($addSQL'cols'),
                
$this->node_table,
                
$this->_addSQL($addSQL'join'),
                
$this->node_table,
                
$this->flparams['rootid'],
                
$this->db->quote($thisnode->rootid),
                
$this->_addSQL($addSQL'append'),
                
$this->node_table,
                
$this->flparams['level'],
                
$this->node_table,
                
$this->secondarySort);

        if (!
$this->_caching) {
            
$nodeSet $this->_processResultSet($sql$keepAsArray$aliasFields);
        } else {
            
$nodeSet $this->cache->call('DB_NestedSet->_processResultSet'$sql$keepAsArray$aliasFields);
        }
        
        
// EVENT (nodeLoad)
        
foreach (array_keys($nodeSet) as $key) {
            
$this->triggerEvent('nodeLoad'$nodeSet[$key]);
        }
        return 
$nodeSet;
    }
    
    
// }}}
    // {{{ getParents()
    
    /**
     * Fetch the parents of a node given by id
     *
     * @param int  $id The node ID
     * @param bool $keepAsArray (optional) Keep the result as an array or transform it into
     *             a set of DB_NestedSet_Node objects?
     * @param bool $aliasFields (optional) Should we alias the fields so they are the names
     *             of the parameter keys, or leave them as is?
     * @param array $addSQL (optional) Array of additional params to pass to the query.
     *
     * @see _addSQL()
     * @access public
     * @return mixed False on error, or an array of nodes
     */
    
function getParents($id$keepAsArray false$aliasFields true$addSQL = array())
    {
        
$this->_debugMessage('getParents($id)');
        if (!(
$child $this->_getNodeObject($id))) {
            return 
false;
        }
        
        
$sql sprintf('SELECT %s %s FROM %s %s 
                        WHERE %s.%s=%s AND %s.%s<%s AND %s.%s<%s AND %s.%s>%s %s 
                        ORDER BY %s.%s ASC'

                        
$this->_getSelectFields($aliasFields),
                        
$this->_addSQL($addSQL'cols'),
                        
$this->node_table,
                        
$this->_addSQL($addSQL'join'),
                        
$this->node_table,
                        
$this->flparams['rootid'],
                        
$child->rootid,
                        
$this->node_table,
                        
$this->flparams['level'],
                        
$child->level,
                        
$this->node_table,
                        
$this->flparams['l'],
                        
$child->l,
                        
$this->node_table,
                        
$this->flparams['r'],
                        
$child->r,
                        
$this->_addSQL($addSQL'append'),
                        
$this->node_table,
                        
$this->flparams['level']);

        if (!
$this->_caching) {
            
$nodeSet $this->_processResultSet($sql$keepAsArray$aliasFields);
        } else {
            
$nodeSet $this->cache->call('DB_NestedSet->_processResultSet'$sql$keepAsArray$aliasFields);
        }
        
        
// EVENT (nodeLoad)
        
foreach (array_keys($nodeSet) as $key) {
            
$this->triggerEvent('nodeLoad'$nodeSet[$key]);
        }
        return 
$nodeSet;
    }
    
    
// }}}
    // {{{ getChildren()
    
    /**
     * Fetch the children _one level_ after of a node given by id
     *
     * @param int  $id The node ID
     * @param bool $keepAsArray (optional) Keep the result as an array or transform it into
     *             a set of DB_NestedSet_Node objects?
     * @param bool $aliasFields (optional) Should we alias the fields so they are the names
     *             of the parameter keys, or leave them as is?
     * @param bool $forceNorder (optional) Force the result to be ordered by the norder
     *             param (as opposed to the value of secondary sort).  Used by the move and
     *             add methods.
     * @param array $addSQL (optional) Array of additional params to pass to the query.
     *
     * @see _addSQL()
     * @access public
     * @return mixed False on error, or an array of nodes
     */
    
function getChildren($id$keepAsArray false$aliasFields true$forceNorder false$addSQL = array())
    {
        
$this->_debugMessage('getChildren($id)');
        
$parent $this->_getNodeObject($id);
        if (!
$parent || $parent->== ($parent->1)) {
            return 
false;
        }
        
        
$orderBy $forceNorder $this->flparams['norder'] : $this->secondarySort;
        
$sql sprintf('SELECT %s %s FROM %s %s 
                        WHERE %s.%s=%s AND %s.%s=%s+1 AND %s.%s BETWEEN %s AND %s %s 
                        ORDER BY %s.%s ASC'
,
                        
$this->_getSelectFields($aliasFields),
                        
$this->_addSQL($addSQL'cols'),
                        
$this->node_table,
                        
$this->_addSQL($addSQL'join'),
                        
$this->node_table,
                        
$this->flparams['rootid'],
                        
$this->db->quote($parent->rootid),
                        
$this->node_table,
                        
$this->flparams['level'],
                        
$parent->level,
                        
$this->node_table,
                        
$this->flparams['l'],
                        
$parent->l,
                        
$parent->r,
                        
$this->_addSQL($addSQL'append'),
                        
$this->node_table,
                        
$orderBy);

        if (!
$this->_caching) {
            
$nodeSet $this->_processResultSet($sql$keepAsArray$aliasFields);
        } else {
            
$nodeSet $this->cache->call('DB_NestedSet->_processResultSet'$sql$keepAsArray$aliasFields);
        }
        
        
// EVENT (nodeLoad)
        
foreach (array_keys($nodeSet) as $key) {
            
$this->triggerEvent('nodeLoad'$nodeSet[$key]);
        }
        return 
$nodeSet;
    }
    
    
// }}}
    // {{{ getSubBranch()
    
    /**
    * Fetch all the children of a node given by id
    *
    * getChildren only queries the immediate children
    * getSubBranch returns all nodes below the given node
    *
    * @param string  $id The node ID
    * @param bool $keepAsArray (optional) Keep the result as an array or transform it into
    *             a set of DB_NestedSet_Node objects?
    * @param bool $aliasFields (optional) Should we alias the fields so they are the names
    *             of the parameter keys, or leave them as is?
    * @param array $addSQL (optional) Array of additional params to pass to the query.
    *
    * @see _addSQL()
    * @access public
    * @return mixed False on error, or an array of nodes
    */
    
function getSubBranch($id$keepAsArray false$aliasFields true$addSQL = array())
    {
        
$this->_debugMessage('getSubBranch($id)');
        if (!(
$parent $this->_getNodeObject($id))) {
            return 
false;
        }
        
        
$sql sprintf('SELECT %s %s FROM %s %s WHERE %s.%s BETWEEN %s AND %s AND %s.%s=%s AND %s.%s!=%s %s',
                
$this->_getSelectFields($aliasFields),
                
$this->_addSQL($addSQL'cols'),
                
$this->node_table,
                
$this->_addSQL($addSQL'join'),
                
$this->node_table,
                
$this->flparams['l'],
                
$parent->l,
                
$parent->r,
                
$this->node_table,
                
$this->flparams['rootid'],
                
$this->db->quote($parent->rootid),
                
$this->node_table,
                
$this->flparams['id'],
                
$this->db->quote($id),
                
$this->_addSQL($addSQL'append'));

        if (!
$this->_caching) {
            
$nodeSet $this->_processResultSet($sql$keepAsArray$aliasFields);
        } else {
            
$nodeSet $this->cache->call('DB_NestedSet->_processResultSet'$sql$keepAsArray$aliasFields);
        }
        
        
// EVENT (nodeLoad)
        
foreach (array_keys($nodeSet) as $key) {
            
$this->triggerEvent('nodeLoad'$nodeSet[$key]);
        }
        return 
$nodeSet;
    }
    
    
// }}}
    // {{{ pickNode()
    
    /**
    * Fetch the data of a node with the given id
    *
    * @param int  $id The node id of the node to fetch
    * @param bool $keepAsArray (optional) Keep the result as an array or transform it into
    *             a set of DB_NestedSet_Node objects?
    * @param bool $aliasFields (optional) Should we alias the fields so they are the names
    *             of the parameter keys, or leave them as is?
    * @param string $idfield (optional) Which field has to be compared with $id?
    *               This is can be used to pick a node by other values (e.g. it's name).
    * @param array $addSQL (optional) Array of additional params to pass to the query.
    *
    * @see _addSQL()
    * @access public
    * @return mixed False on error, or an array of nodes
    */
    
function pickNode($id$keepAsArray false$aliasFields true$idfield 'id'$addSQL = array())
    {
        
$this->_debugMessage('pickNode($id)');
        if (
is_object($id) && $id->id) {
            
$id $id->id;
        }
        
        
$sql sprintf('SELECT %s %s FROM %s %s WHERE %s.%s=%s %s',
                
$this->_getSelectFields($aliasFields),
                
$this->_addSQL($addSQL'cols'),
                
$this->node_table,
                
$this->_addSQL($addSQL'join'),
                
$this->node_table,
                
$this->flparams[$idfield],
                
$this->db->quote($id),
                
$this->_addSQL($addSQL'append'));

        if (!
$this->_caching) {
            
$nodeSet $this->_processResultSet($sql$keepAsArray$aliasFields);
        } else {
            
$nodeSet $this->cache->call('DB_NestedSet->_processResultSet'$sql$keepAsArray$aliasFields);
        }
        
        
$nsKey false;
        
// EVENT (nodeLoad)
        
foreach (array_keys($nodeSet) as $key) {
            
$this->triggerEvent('nodeLoad'$nodeSet[$key]);
            
$nsKey $key;
        }
        
        if (
is_array($nodeSet) && $idfield != 'id') {
            
$id $nsKey;
        }
        
        return isset(
$nodeSet[$id]) ? $nodeSet[$id] : false;
    }
    
    
// }}}
    // {{{ isParent()
    
    /**
     * See if a given node is a parent of another given node
     *
     * A node is considered to be a parent if it resides above the child
     * So it doesn't mean that the node has to be an immediate parent.
     * To get this information simply compare the levels of the two nodes
     * after you know that you have a parent relation.
     *
     * @param mixed  $parent The parent node as array or object
     * @param mixed  $child  The child node as array or object
     *
     * @access public
     * @return bool True if it's a parent
     */
    
function isParent($parent$child) {
        
        
$this->_debugMessage('isParent($parent, $child)');
        
        if (!isset(
$parent)|| !isset($child)) {
            return 
false;
        }
        
        if (
is_array($parent)) {
            
$p_rootid     $parent['rootid'];
            
$p_l        $parent['l'];
            
$p_r        $parent['r'];
            
        } elseif (
is_object($parent)) {
            
$p_rootid     $parent->rootid;
            
$p_l        $parent->l;
            
$p_r        $parent->r;
        }
        
        if (
is_array($child)) {
            
$c_rootid     $child['rootid'];
            
$c_l        $child['l'];
            
$c_r        $child['r'];
        } elseif (
is_object($child)) {
            
$c_rootid     $child->rootid;
            
$c_l        $child->l;
            
$c_r        $child->r;
        }
        
        if ((
$p_rootid == $c_rootid) && ($p_l $c_l && $p_r $c_r)) {
            return 
true;
        }
        
        return 
false;
    }
    
    
// }}}
    // {{{ _processResultSet()
    
    /**
    * Processes a DB result set by checking for a DB error and then transforming the result
    * into a set of DB_NestedSet_Node objects or leaving it as an array.
    *
    * @param string $sql The sql query to be done
    * @param bool $keepAsArray Keep the result as an array or transform it into a set of
    *             DB_NestedSet_Node objects?
    * @param bool $fieldsAreAliased Are the fields aliased?
    *
    * @access    private
    * @return mixed False on error or the transformed node set.
    */
    
function _processResultSet($sql$keepAsArray$fieldsAreAliased)
    {
        
$result $this->db->getAll($sql);
        if (
$this->_testFatalAbort($result__FILE____LINE__)) {
            return 
false;
        }
        
        
$nodes = array();
        
$idKey $fieldsAreAliased 'id' $this->flparams['id'];
        foreach (
$result as $row) {
            
$node_id $row[$idKey];
            if (
$keepAsArray) {
                
$nodes[$node_id] = $row;
            } else {
                
// Create an instance of the node container
                
$nodes[$node_id] =& new DB_NestedSet_Node($row);
            }
            
        }
        
        return 
$nodes;
    }
    
    
// }}}
    // {{{ _getNodeObject()
    
    /**
    * Gets the node to work on based upon an id
    *
    * @param mixed $id The id which can be an object or integer
    *
    * @access private
    * @return mixed The node object for an id or false on error
    */
    
function _getNodeObject($id)
    {
        if (!
is_object($id) || !$id->id) {
            return 
$this->pickNode($id);
        }
        else {
            return 
$id;
        }
    }
    
    
// }}}
    // {{{ _addSQL()

    /**
     * Adds a specific type of SQL to a query string
     *
     * @param array $addSQL The array of SQL strings to add.  Example value:
     *               $addSQL = array(
     *               'cols' => 'tb2.col2, tb2.col3',         // Additional tables/columns
     *               'join' => 'LEFT JOIN tb1 USING(STRID)', // Join statement
     *               'append' => 'GROUP by tb1.STRID');      // Group condition
     * @param string $type The type of SQL.  Can be 'cols', 'join', or 'append'.
     *
     * @access private
     * @return string The SQL, properly formatted
     */
    
function _addSQL($addSQL$type
    {
        if (!isset(
$addSQL[$type])) {
            return 
'';
        }        
        
        switch(
$type) {
            case 
'cols':
                return 
', ' $addSQL[$type];
            break;    
            default:
                return 
$addSQL[$type];
            break;
        }
    }

    
// }}}
    // {{{ _getSelectFields()
    
    /**
    * Gets the select fields based on the params
    *
    * @param bool $aliasFields Should we alias the fields so they are the names of the
    *             parameter keys, or leave them as is?
    *
    * @access private
    * @return string A string of query fields to select
    */
    
function _getSelectFields($aliasFields)
    {
        
$queryFields = array();
        foreach (
$this->params as $key => $val) {
            
$tmp_field $this->node_table '.' $key;
            if (
$aliasFields) {
                
$tmp_field .= ' AS ' $val;
            }
            
$queryFields[] = $tmp_field;
        }

        
$fields implode(', '$queryFields);
        return 
$fields;
    }
    
    
// }}}
    // +----------------------------------------------+
    // | NestedSet manipulation and query methods     |
    // |----------------------------------------------+
    // | insert / delete / update of nodes            |
    // +----------------------------------------------+
    // | [PUBLIC]                                     |
    // +----------------------------------------------+
    // {{{ createRootNode()
    
    /**
    * Creates a new root node
    * Optionally it deletes the whole tree and creates one initial rootnode
    *
    * <pre>
    * +-- root1 [target]
    * |
    * +-- root2 [new]
    * |
    * +-- root3
    * </pre>
    *
    * @param array    $values      Hash with param => value pairs of the node (see $this->params)
    * @param integer  $id          ID of target node (the rootnode after which the node should be inserted)
    * @param bool     $first       Danger: Deletes and (re)init's the hole tree - sequences are reset
    *
    * @access public
    * @return int The node id
    */
    
function createRootNode($values$id false$first false)
    {
        
$this->_debugMessage('createRootNode($values, $id = false, $first = false)');
        
// Try to aquire a table lock
        
if(PEAR::isError($lock=$this->_setLock())) {
            return 
$lock;
        }
        
        
$flft $this->flparams['l'];
        
$frgt $this->flparams['r'];
        
$froot $this->flparams['rootid'];
        
$fid $this->flparams['id'];
        
$freh $this->flparams['norder'];
        
$flevel $this->flparams['level'];
        
$tb $this->node_table;
        
$addval = array();
        
$addval[$flevel] = 1;
        
// Shall we delete the existing tree (reinit)
        
if ($first) {
            
$sql "DELETE FROM $tb";
            
$this->db->query($sql);
            
$this->db->dropSequence($this->sequence_table);
            
// New order of the new node will be 1
            
$addval[$freh] = 1;
        } else {
            
// Let's open a gap for the new node
            
$parent $this->pickNode($id);
            if (!
$parent) {
                
// invalid parent node, order will be 1
                
$addval[$freh] = 1;
                
// no gap to make
                
$first true;
            }
            else {
                
$addval[$freh] = $parent->norder 1;
            }
        }
        
        
// Sequence of node id (equals to root id in this case
        
$addval[$froot] = $node_id $addval[$fid] = $this->db->nextId($this->sequence_table);
        
// Left/Right values for rootnodes
        
$addval[$flft] = 1;
        
$addval[$frgt] = 2;
        
// Transform the node data hash to a query
        
if (!$qr $this->_values2Query($values$addval)) {
            return 
false;
        }
        
        if (!
$first) {
            
// Open the gap
            
$sql "UPDATE $tb SET $freh=$freh+1 WHERE $fid=$froot AND $freh>$parent->norder";
            
$res $this->db->query($sql);
            
$this->_testFatalAbort($res__FILE__,  __LINE__);
        }
        
        
// Insert the new node
        
$sql "INSERT INTO $tb SET $qr";
        
$res $this->db->query($sql);
        
$this->_testFatalAbort($res__FILE__,  __LINE__);
        
        
// EVENT (nodeCreate)
        
$thisnode = &$this->pickNode($node_id);
        
$this->triggerEvent('nodeCreate'$thisnode);
        return 
$node_id;
    }
    
    
// }}}
    // {{{ createSubNode()
    
    /**
    * Creates a subnode
    *
    * <pre>
    * +-- root1
    * |
    * +-\ root2 [target]
    * | |
    * | |-- subnode1 [new]
    * |
    * +-- root3
    * </pre>
    *
    * @param integer    $id          Parent node ID
    * @param array      $values      Hash with param => value pairs of the node (see $this->params)
    *
    * @access public
    * @return mixed The node id or false on error
    */
    
function createSubNode($id$values)
    {
        
$this->_debugMessage('createSubNode($id, $values)');
        
// Try to aquire a table lock
        
if(PEAR::isError($lock $this->_setLock())) {
            return 
$lock;
        }
        
        
$freh $this->flparams['norder'];
        
$flevel $this->flparams['level'];
        
// Get the children of the target node
        
$children $this->getChildren($idfalsetruetrue);
        
// We have children here
        
if ($children) {
            
// Get the last child
            
$last array_pop($children);
            
// What we have to do is virtually an insert of a node after the last child
            // So we don't have to proceed creating a subnode
            
$newNode =& $this->createRightNode($last->id$values);
            return 
$newNode;
        }
        
        
// invalid parent id, bail out
        
if (!($thisnode $this->pickNode($id))) {
            
$this->raiseError("Parent id: $id not found"NESE_ERROR_NOT_FOUNDPEAR_ERROR_TRIGGERE_USER_ERROR);
            return 
false;
        }
        
        
$flft $this->flparams['l'];
        
$frgt $this->flparams['r'];
        
$froot $this->flparams['rootid'];
        
$fid $this->flparams['id'];
        
$lft $thisnode->l;
        
$rgt $thisnode->r;
        
$rootid $thisnode->rootid;
        
$plevel $thisnode->level;
        
$tb $this->node_table;
        
        
// Open the gap
        
$sql "UPDATE $tb SET $flft=$flft+2
                WHERE 
$froot=" $this->db->quote($rootid) . " AND 
                
$flft>" $this->db->quote($rgt) . " AND 
                
$frgt>=" $this->db->quote($rgt);
        
$res $this->db->query($sql);
        
$this->_testFatalAbort($res__FILE__,  __LINE__);
        
        
$sql "UPDATE $tb SET $frgt=$frgt+2
                WHERE 
$froot=" $this->db->quote($rootid) . " AND 
                
$frgt>=" $this->db->quote($rgt);
        
$res $this->db->query($sql);
        
$this->_testFatalAbort($res__FILE__,  __LINE__);
        
        
$addval = array();
        
$addval[$flft] = $rgt;
        
$addval[$frgt] = $rgt 1;
        
$addval[$froot] = $rootid;
        
$addval[$freh] = 1;
        
$addval[$flevel] = $plevel 1;
        
$node_id $addval[$fid] = $this->db->nextId($this->sequence_table);
        if (!
$qr $this->_values2Query($values$addval)) {
            return 
false;
        }
        
        
$sql "INSERT INTO $tb SET $qr";
        
$res $this->db->query($sql);
        
$this->_testFatalAbort($res__FILE__,  __LINE__);
        
        
// EVENT (NodeCreate)
        
$thisnode $this->pickNode($node_id);
        
$this->triggerEvent('nodeCreate'$thisnode);
        return 
$node_id;
    }
    
    
// }}}
    // {{{ createRightNode()
    
    /**
    * Creates a node after a given node
    * <pre>
    * +-- root1
    * |
    * +-\ root2
    * | |
    * | |-- subnode1 [target]
    * | |-- subnode2 [new]
    * | |-- subnode3
    * |
    * +-- root3
    * </pre>
    *
    * @param int   $target        Target node ID
    * @param array      $values      Hash with param => value pairs of the node (see $this->params)
    *
    * @access public
    * @return object The new node object
    */
    
function createRightNode($target$values)
    {
        
$this->_debugMessage('createRightNode($target, $values)');
        if(
PEAR::isError($lock=$this->_setLock())) {
            return 
$lock;
        }
        
        
$id $target;
        
$flft $this->flparams['l'];
        
$frgt $this->flparams['r'];
        
$froot $this->flparams['rootid'];
        
$freh $this->flparams['norder'];
        
$fid $this->flparams['id'];
        
$flevel $this->flparams['level'];
        
// invalid target node, bail out
        
if (!($thisnode $this->pickNode($id))) {
            
$this->raiseError("Target id: $id not found"NESE_ERROR_NOT_FOUNDPEAR_ERROR_TRIGGERE_USER_ERROR);
            return 
false;
        }
        
        
// If the target node is a rootnode we virtually want to create a new root node
        
if ($thisnode->rootid == $thisnode->id) {
            return 
$this->createRootNode($values$id);
        }
        
        
$lft $thisnode->l;
        
$rgt $thisnode->r;
        
$rootid $thisnode->rootid;
        
$level $thisnode->level;
        
$parent_order $thisnode->norder;
        
$tb $this->node_table;
        
$addval = array();
        
$parents $this->getParents($id);
        
$parent array_pop($parents);
        
$plft $parent->l;
        
$prgt $parent->r;
        
// Open the gap within the current level
        
$sql "UPDATE $tb SET $freh=$freh+1
                WHERE 
$froot=" $this->db->quote($rootid) . " AND 
                
$freh>$parent_order AND 
                
$flevel=$level AND 
                
$flft BETWEEN $plft AND $prgt";
               
        
$res $this->db->query($sql);
        
$this->_testFatalAbort($res__FILE__,  __LINE__);
        
        
// Update all nodes which have dependent left and right values
        
$sql "UPDATE $tb SET
                
$flft=IF($flft>$rgt$flft+2, $flft),
                
$frgt=IF($frgt>$rgt$frgt+2, $frgt)
                WHERE 
$froot=" $this->db->quote($rootid) . "
                AND 
$frgt>" $this->db->quote($rgt);
        
$res $this->db->query($sql);
        
$this->_testFatalAbort($res__FILE__,  __LINE__);
        
        
$addval[$freh] = $parent_order 1;
        
$addval[$flft] = $rgt 1;
        
$addval[$frgt] = $rgt 2;
        
$addval[$froot] = $rootid;
        
$addval[$flevel] = $level;
        
$node_id $addval[$fid] = $this->db->nextId($this->sequence_table);
        if (!
$qr $this->_values2Query($values$addval)) {
            return 
false;
        }
        
        
// Insert the new node
        
$sql "INSERT INTO $tb SET $qr";
        
$res $this->db->query($sql);
        
$this->_testFatalAbort($res__FILE__,  __LINE__);
        
        
// EVENT (NodeCreate)
        
$thisnode =& $this->pickNode($node_id);
        
$this->triggerEvent('nodeCreate'$thisnode);
        return 
$node_id;
    }
    
    
// }}}
    // {{{ deleteNode()
    
    /**
    * Deletes a node
    *
    * @param int $id ID of the node to be deleted
    *
    * @access public
    * @return bool True if the delete succeeds
    */
    
function deleteNode($id)
    {
        
$this->_debugMessage('deleteNode($id)');
        if (
PEAR::isError($lock $this->_setLock())) {
            return 
$lock;
        }
        
        if (!(
$thisnode $this->pickNode($id))) {
            return 
false;
        }
        
        
// EVENT (NodeDelete)
        
$this->triggerEvent('nodeDelete'$thisnode);
        
        
$parents $this->getParents($id);
        
$parent array_pop($parents);
        
$plft $parent->l;
        
$prgt $parent->r;
                
        
$tb $this->node_table;
        
$flft $this->flparams['l'];
        
$frgt $this->flparams['r'];
        
$fid $this->flparams['id'];
        
$froot $this->flparams['rootid'];
        
$freh $this->flparams['norder'];
        
$flevel $this->flparams['level'];
        
$lft $thisnode->l;
        
$rgt $thisnode->r;
        
$order $thisnode->norder;
        
$level $thisnode->level;
        
$rootid $thisnode->rootid;
        
$len $rgt $lft 1;
        
// Delete the node
        
$sql "DELETE from $tb WHERE $flft BETWEEN $lft AND $rgt AND $froot=" $this->db->quote($rootid);
        
$this->db->query($sql);
        
        if (
$thisnode->id != $thisnode->rootid) {
            
// The node isn't a rootnode so close the gap
            
$sql "UPDATE $tb SET
                    
$flft=IF($flft>$lft$flft-$len$flft),
                    
$frgt=IF($frgt>$lft$frgt-$len$frgt)
                    WHERE 
$froot=" $this->db->quote($rootid) . " AND 
                    (
$flft>$lft OR $frgt>$rgt)";
            
$res $this->db->query($sql);
            
$this->_testFatalAbort($res__FILE__,  __LINE__);
            
            
// Re-order
            
$sql "UPDATE $tb SET $freh=$freh-1
                    WHERE 
$froot=" $this->db->quote($rootid) . " AND 
                    
$flevel=$level AND 
                    
$freh>$order AND
                    
$flft BETWEEN $plft AND $prgt";

            
$res $this->db->query($sql);
            
$this->_testFatalAbort($res__FILE__,  __LINE__);
        } else {
            
// A rootnode was deleted and we only have to close the gap inside the order
            
$sql "UPDATE $tb SET $freh=$freh-1 WHERE $froot=$fid AND $freh > $order";
            
$res $this->db->query($sql);
            
$this->_testFatalAbort($res__FILE__,  __LINE__);
        }
        
        return 
true;
    }
    
    
// }}}
    // {{{ updateNode()
    
    /**
    * Changes the payload of a node
    *
    * @param int    $id Node ID
    * @param array  $values Hash with param => value pairs of the node (see $this->params)
    *
    * @access public
    * @return bool True if the update is successful
    */
    
function updateNode($id$values)
    {
        
$this->_debugMessage('updateNode($id, $values)');
        if (
PEAR::isError($lock $this->_setLock())) {
            return 
$lock;
        }
        
        if (!(
$thisnode =& $this->pickNode($id))) {
            return 
false;
        }
        
        
$eparams = array('values' => $values);
        
// EVENT (NodeUpdate)
        
$this->triggerEvent('nodeUpdate'$thisnode$eparams);
        
$fid $this->flparams['id'];
        
$addvalues = array();
        if (!
$qr $this->_values2Query($values$addvalues)) {
            return 
false;
        }
        
        
$sql "UPDATE $this->node_table SET $qr WHERE $fid=" $this->db->quote($id);
        
$res $this->db->query($sql);
        
$this->_testFatalAbort($res__FILE__,  __LINE__);
        return 
true;
    }
    
    
// }}}
    // +----------------------------------------------+
    // | Moving and copying                           |
    // |----------------------------------------------+
    // | [PUBLIC]                                     |
    // +----------------------------------------------+
    // {{{ moveTree()
    
    /**
    * Wrapper for node moving and copying
    *
    * @param int    $id Source ID
    * @param int    $target Target ID
    * @param array  $pos Position (use one of the NESE_MOVE_* constants)
    * @param bool   $copy Shall we create a copy
    *
    * @see _moveInsideLevel
    * @see _moveAcross
    * @see moveRoot2Root
    * @access public
    * @return int ID of the moved node or false on error
    */
    
function moveTree($id$target$pos$copy false)
    {
        
$this->_debugMessage('moveTree($id, $target, $pos, $copy = false)');
        if (
PEAR::isError($lock $this->_setLock())) {
            return 
$lock;
        }

        
// This operations don't need callbacks except the copy handler
        // which ignores this setting
        
$this->skipCallbacks true;
        
// Get information about source and target
        
if (!($source $this->pickNode($id))) {
            
$this->raiseError("Node id: $id not found"NESE_ERROR_NOT_FOUNDPEAR_ERROR_TRIGGERE_USER_ERROR);
            return 
false;
        }
        
        if (!(
$target $this->pickNode($target))) {
            
$this->raiseError("Target id: $target not found"NESE_ERROR_NOT_FOUNDPEAR_ERROR_TRIGGERE_USER_ERROR);
            return 
false;
        }
        
        
// We have a recursion - let's stop
        
if (($target->rootid == $source->rootid) &&
        ((
$source-><= $target->l) &&
        (
$source->>= $target->r))) {
            
            return new 
PEAR_Error($this->_getMessage(NESE_ERROR_RECURSION),NESE_ERROR_RECURSION);
        }
        
        
// Insert/move before or after
        
if ($pos == NESE_MOVE_BEFORE || $pos == NESE_MOVE_AFTER) {
            if ((
$source->rootid == $source->id) &&
            (
$target->rootid == $target->id) &&
            !
$copy) {
                
// We have to move a rootnode which is different from moving inside a tree
                
return $this->moveRoot2Root($source$target$pos$copy);
            }
            
            if ((
$source->rootid == $target->rootid) &&
            (
$source->level == $target->level)) {
                
// We have to move inside the same subtree and inside the same level - no big deal
                
return $this->_moveInsideLevel($source$target$pos$copy);
            }
        }
        
        
// We have to move between different levels and maybe subtrees - let's rock ;)
        
return $this->_moveAcross($source$target$pos$copy);
    }
    
    
// }}}
    // {{{ _moveAcross()
    
    /**
    * Moves nodes and trees to other subtrees or levels
    *
    * <pre>
    * [+] <--------------------------------+
    * +-[\] root1 [target]                 |
    *     <-------------------------+      |
    * +-\ root2                     |      |
    * | |                           |      |
    * | |-- subnode1 [target]       |      |B
    * | |-- subnode2 [new]          |S     |E
    * | |-- subnode3                |U     |F
    * |                             |B     |O
    * +-\ root3                     |      |R
    *   |-- subnode 3.1             |      |E
    *   |-\ subnode 3.2 [source] >--+------+
    *     |-- subnode 3.2.1
    *</pre>
    *
    * @param     object NodeCT $source   Source node
    * @param     object NodeCT $target   Target node
    * @param     string    $pos          Position [SUBnode/BEfore]
    * @param     bool         $copy                Shall we create a copy
    *
    * @access    private
    * @see        moveTree
    * @see        _r_moveAcross
    * @see        _moveCleanup
    */
    
function _moveAcross($source$target$pos$copy false)
    {
        
$this->_debugMessage('_moveAcross($source, $target, $pos, $copy = false)');
        if (
PEAR::isError($lock $this->_setLock())) {
            return 
$lock;
        }
        
        
$tb $this->node_table;
        
$flft $this->flparams['l'];
        
$frgt $this->flparams['r'];
        
$fid $this->flparams['id'];
        
$froot $this->flparams['rootid'];
        
$freh $this->flparams['norder'];
        
$s_id $source->id;
        
$t_id $target->id;
        
$rootid $target->rootid;
        
// Get the current data from a node and exclude the id params which will be changed
        // because of the node move
        
foreach($this->params as $key => $val) {
            if (
$source->$val && !in_array($val$this->requiredParams)) {
                
$values[$key] = trim($source->$val);
            }
        }
        
        if (
$pos != NESE_MOVE_BELOW) {
            
$c_id $this->createRightNode($t_id$values);
            
$clone $this->pickNode($c_id);
            if (
$pos == NESE_MOVE_BEFORE) {
                
$this->moveTree($c_id$t_id$pos);
            }
        } else {
            
$c_id $this->createSubNode($t_id$values);
            
$clone $this->pickNode($c_id);
        }
        
        
$relations[$s_id] = $c_id;

        
$children $this->getChildren($sourcefalsetruetrue);
        
$first true;
        if (
$children) {
            
// Recurse trough the child nodes
            
foreach($children AS $key => $val) {
                if (
$first) {
                    
$first false;
                    
$previd $this->_r_moveAcross($val$clone'createSubNode'$relations);
                } else {
                    
$sister $this->pickNode($previd);
                    
$previd $this->_r_moveAcross($val$sister'createRightNode'$relations);
                }
            }
        }

        
$this->_moveCleanup($relations$copy);
        if(!
$copy) {
            return 
$source->id;
        } else {
            return 
$clone->id;
        }
    }
    
    
// }}}
    // {{{ _r_moveAcross()
    
    /**
    * Recursion for _moveAcross
    *
    * @param     object     NodeCT $source    Source
    * @param     object     NodeCT $target    Target
    * @param     string    $action            createRightNode|createSubNode
    * @param     array    $relations        Hash $h[old ID]=new ID - maps the source node to the new created node (clone)
    * @access    private
    * @see        _moveAcross
    */
    
function _r_moveAcross($source$target$action, &$relations) {
        
$this->_debugMessage('_r_moveAcross($source, $target, $action, &$relations)');
        if (
PEAR::isError($lock $this->_setLock())) {
            return 
$lock;
        }
        
        foreach(
$this->params AS $key => $val) {
            if (
$source->$val && !in_array($val$this->requiredParams)) {
                
$values[$key] = trim($source->$val);
            }
        }
        
        
$s_id $source->id;
        
$t_id $target->id;
        
$c_id $this->$action($t_id$values);
        
$relations[$s_id] = $c_id;
        
$children $this->getChildren($sourcefalsetruetrue);
        if (!
$children) {
            return 
$c_id;
        }
        
        
$clone $this->pickNode($c_id);
        
$first true;
        foreach(
$children as $key => $val) {
            if (
$first) {
                
$first false;
                
$previd =
                
$this->_r_moveAcross($val$clone'createSubNode'$relations);
            } else {
                
$sister $this->pickNode($previd);
                
$previd $this->_r_moveAcross($val$sister'createRightNode'$relations);
            }
        }
        
        return 
$c_id;
    }
    
    
// }}}
    // {{{ _moveCleanup()
    
    /**
    * Deletes the old subtree (node) and writes the node id's into the cloned tree
    *
    *
    * @param     array    $relations        Hash in der Form $h[alteid]=neueid
    * @param     array    $copy                     Are we in copy mode?
    * @access    private
    */
    
function _moveCleanup($relations$copy false)
    {
        
$this->_debugMessage('_moveCleanup($relations, $copy = false)');
        if (
PEAR::isError($lock $this->_setLock())) {
            return 
$lock;
        }
        
        
$tb $this->node_table;
        
$fid $this->flparams['id'];
        
$froot $this->flparams['rootid'];
        foreach(
$relations AS $key => $val) {
            
$clone $this->pickNode($val);
            if (
$copy) {
                
// EVENT (NodeCopy)
                
$thisnode =& $this->pickNode($key);
                
$eparams = array('clone' => $clone);
                
$this->triggerEvent('nodeCopy'$thisnode$eparams);
                continue;
            }
            
            
// No callbacks here because the node itself doesn't get changed
            // Only it's position
            // If one needs a callback here please let me know
            
$this->skipCallbacks true;
            
$this->deleteNode($keytrue);
            
// It's isn't a rootnode
            
if ($clone->id != $clone->rootid) {
                
$u_values = array();
                
$u_id $val;
                
$u_values[$fid] = $key;
                
$this->updateNode($u_id$u_values);
            } else {
                
$sql "UPDATE $tb SET
                            
$fid=" $this->db->quote($key) . ",
                            
$froot=" $this->db->quote($key) . 
                        WHERE 
$fid=" $this->db->quote($val);
                
$this->db->query($sql);
                
$orootid $clone->rootid;
                
$sql "UPDATE $tb
                        SET 
$froot=" $this->db->quote($key) . "
                        WHERE 
$froot=" $this->db->quote($orootid);
                
$this->db->query($sql);
            }
            
            
$this->skipCallbacks false;
        }
        
        return 
true;
    }
    
    
// }}}
    // {{{ _moveInsideLevel()
    
    /**
    * Moves a node or subtree inside the same level
    *
    * <pre>
    * +-- root1
    * |
    * +-\ root2
    * | |
    * | |-- subnode1 [target]
    * | |-- subnode2 [new]
    * | |-- subnode3
    * |
    * +-\ root3
    *  [|]  <-----------------------+
    *   |-- subnode 3.1 [target]    |
    *   |-\ subnode 3.2 [source] >--+
    *     |-- subnode 3.2.1
    * </pre>
    *
    * @param     object NodeCT $source    Source
    * @param     object NodeCT $target    Target
    * @param     string $pos              BEfore | AFter
    * @param     string $copy             Copy mode?
    * @access    private
    * @see        moveTree
    */
    
function _moveInsideLevel($source$target$pos$copy false)
    {
        
$this->_debugMessage('_moveInsideLevel($source, $target, $pos, $copy = false)');
        if (
PEAR::isError($lock=$this->_setLock())) {
            return 
$lock;
        }
        
        
// If we only want to copy it's quite easy cause no gap will occur as in move mode
        
if ($copy) {
            
$parents $this->getParents($target->id);
            
$ntarget = @array_pop($parents);
            if (
is_object($ntarget)) {
                
$npos NESE_MOVE_BELOW;
            } else {
                
$npos $pos;
                
$ntarget $target;
            }
            
            
// Let's move the node to it's destination
            
$nroot $this->_moveAcross($source$ntarget$npos$copy);
            
// Change the order
            
return $this->moveTree($nroot$target->id$pos);
        }
        
        
$parents $this->getParents($source);
        
$parent array_pop($parents);
        
$plft $parent->l;
        
$prgt $parent->r;
        
$tb $this->node_table;
        
$flft $this->flparams['l'];
        
$frgt $this->flparams['r'];
        
$fid $this->flparams['id'];
        
$froot $this->flparams['rootid'];
        
$freh $this->flparams['norder'];
        
$flevel $this->flparams['level'];
        
$s_order $source->norder;
        
$t_order $target->norder;
        
$level $source->level;
        
$rootid $source->rootid;
        
$s_id $source->id;
        
$t_id $target->id;
        
        if (
$s_order $t_order) {
            if (
$pos == NESE_MOVE_BEFORE) {
                
$sql "UPDATE $tb SET $freh=$freh-1
                        WHERE 
$freh BETWEEN $s_order AND $t_order 
                            AND 
                            
$fid!=$t_id
                            AND 
                            
$fid!=$s_id
                            AND 
                            
$flevel=" $this->db->quote($level) . "
                            AND 
                            
$froot=" $this->db->quote($rootid) . 
                            AND 
                            
$flft BETWEEN $plft AND $prgt";
                
$res $this->db->query($sql);
                
$this->_testFatalAbort($res__FILE____LINE__);
                
                
$sql "UPDATE $tb SET $freh=$t_order-1 WHERE $fid=$s_id";
                
$res $this->db->query($sql);
                
$this->_testFatalAbort($res__FILE____LINE__);
            }
            elseif (
$pos == NESE_MOVE_AFTER) {
                
$sql "UPDATE $tb SET $freh=$freh-1
                        WHERE 
$freh BETWEEN $s_order AND $t_order 
                            AND 
                            
$fid!=$s_id 
                            AND 
                            
$flevel=" $this->db->quote($level) . "
                            AND
                            
$froot=" $this->db->quote($rootid) . 
                            AND 
                            
$flft BETWEEN $plft AND $prgt";  
                
$res $this->db->query($sql);
                
$this->_testFatalAbort($res__FILE____LINE__);
                
                
$sql "UPDATE $tb SET $freh=$t_order WHERE $fid = $s_id";
                
$res $this->db->query($sql);
                
$this->_testFatalAbort($res__FILE____LINE__);
            }
        }
        
        if (
$s_order $t_order) {
            if (
$pos == NESE_MOVE_BEFORE) {
                
$sql "UPDATE $tb SET $freh=$freh+1
                        WHERE 
$freh BETWEEN $t_order AND $s_order 
                            AND 
                            
$fid != $s_id
                            AND 
                            
$froot=" $this->db->quote($rootid) . "
                            AND 
                            
$flevel=" $this->db->quote($level) . "
                            AND 
                            
$flft BETWEEN $plft AND $prgt";
                
$res $this->db->query($sql);
                
$this->_testFatalAbort($res__FILE____LINE__);
                
                
$sql "UPDATE $tb SET $freh=$t_order WHERE $fid=$s_id";
                
$res $this->db->query($sql);
                
$this->_testFatalAbort($res__FILE____LINE__);
            }
            elseif (
$pos == NESE_MOVE_AFTER) {
                
$sql "UPDATE $tb SET $freh=$freh+1
                        WHERE 
$freh BETWEEN $t_order AND $s_order 
                            AND 
                            
$fid!=$t_id
                            AND 
                            
$fid!=$s_id
                            AND 
                            
$froot=" $this->db->quote($rootid) . "
                            AND 
                            
$flevel=" $this->db->quote($level) . "
                            AND 
                            
$flft BETWEEN $plft AND $prgt";
                
$res $this->db->query($sql);
                
$this->_testFatalAbort($res__FILE____LINE__);
                
                
$sql "UPDATE $tb SET $freh=$t_order+1 WHERE $fid=$s_id";
                
$res $this->db->query($sql);
                
$this->_testFatalAbort($res__FILE____LINE__);
            }
        }
        
        return 
$source->id;
    }
    
    
// }}}
    // {{{ moveRoot2Root()
    
    /**
    * Moves rootnodes
    *
    * <pre>
    * +-- root1
    * |
    * +-\ root2
    * | |
    * | |-- subnode1 [target]
    * | |-- subnode2 [new]
    * | |-- subnode3
    * |
    * +-\ root3
    *  [|]  <-----------------------+
    *   |-- subnode 3.1 [target]    |
    *   |-\ subnode 3.2 [source] >--+
    *     |-- subnode 3.2.1
    * </pre>
    *
    * @param     object NodeCT $source    Source
    * @param     object NodeCT $target    Target
    * @param     object NodeCT $target    Parent
    * @param     string $pos              BEfore | AFter
    * @param     string $copy             Copy mode?
    * @access    private
    * @see        moveTree
    */
    
function moveRoot2Root($source$target$pos$copy)
    {
        
$this->_debugMessage('moveRoot2Root($source, $target, $pos, $copy)');
        if(
PEAR::isError($lock=$this->_setLock())) {
            return 
$lock;
        }
        
        
$tb $this->node_table;
        
$flft $this->flparams['l'];
        
$frgt $this->flparams['r'];
        
$fid $this->flparams['id'];
        
$froot $this->flparams['rootid'];
        
$freh $this->flparams['norder'];
        
$s_order $source->norder;
        
$t_order $target->norder;
        
$s_id $source->id;
        
$t_id $target->id;
        
        if (
$s_order $t_order) {
            if (
$pos == NESE_MOVE_BEFORE) {
                
$sql "UPDATE $tb SET $freh=$freh-1
                        WHERE 
$freh BETWEEN $s_order AND $t_order AND 
                            
$fid!=$t_id AND 
                            
$fid!=$s_id AND 
                            
$froot=$fid";
                
$res $this->db->query($sql);
                
$this->_testFatalAbort($res__FILE____LINE__);
                
$sql "UPDATE $tb SET $freh=$t_order -1 WHERE $fid=$s_id";
                
$res $this->db->query($sql);
                
$this->_testFatalAbort($res__FILE____LINE__);
            }
            elseif(
$pos == NESE_MOVE_AFTER) {
                
                
$sql "UPDATE $tb SET $freh=$freh-1
                        WHERE 
$freh BETWEEN $s_order AND $t_order AND 
                            
$fid!=$s_id AND 
                            
$froot=$fid";
                
$res $this->db->query($sql);
                
$this->_testFatalAbort($res__FILE____LINE__);
                
                
$sql "UPDATE $tb SET $freh=$t_order WHERE $fid=$s_id";
                
$res $this->db->query($sql);
                
$this->_testFatalAbort($res__FILE____LINE__);
            }
        }
        
        if (
$s_order $t_order) {
            if (
$pos == NESE_MOVE_BEFORE) {
                
$sql "UPDATE $tb SET $freh=$freh+1
                        WHERE 
$freh BETWEEN $t_order AND $s_order AND 
                            
$fid != $s_id AND 
                            
$froot=$fid";
                
$res $this->db->query($sql);
                
$this->_testFatalAbort($res__FILE____LINE__);
                
                
$sql "UPDATE $tb SET $freh=$t_order WHERE $fid=$s_id";
                
$res $this->db->query($sql);
                
$this->_testFatalAbort($res__FILE____LINE__);
            }
            elseif (
$pos == NESE_MOVE_AFTER) {
                
$sql "UPDATE $tb SET $freh=$freh+1
                        WHERE 
$freh BETWEEN $t_order AND $s_order AND 
                        
$fid!=$t_id AND 
                        
$fid!=$s_id AND 
                        
$froot=$fid";
                
$res $this->db->query($sql);
                
$this->_testFatalAbort($res__FILE____LINE__);
                
                
$sql "UPDATE $tb SET $freh=$t_order+1 WHERE $fid = $s_id";
                
$res $this->db->query($sql);
                
$this->_testFatalAbort($res__FILE____LINE__);
            }
        }
        
        return 
$source->id;
    }
    
    
// }}}
    // +-----------------------+
    // | Helper methods        |
    // +-----------------------+
    // {{{ _testFatalAbort()
    
    /**
    * Error Handler
    *
    * Tests if a given ressource is a PEAR error object
    * ans raises a fatal error in case of an error object
    *
    * @param        object  PEAR::Error $errobj     The object to test
    * @param        string  $file   The filename wher the error occured
    * @param        int     $line   The line number of the error
    * @return   void
    * @access private
    */
    
function _testFatalAbort($errobj$file$line)
    {
        if (!
PEAR::isError($errobj)) {
            return 
false;
        }
        
        
$this->_debugMessage('_testFatalAbort($errobj, $file, $line)');
        if (
$this->debug) {
            
$message $errobj->getUserInfo();
            
$code $errobj->getCode();
            
$msg "$message ($code) in file $file at line $line";
        } else {
            
$msg $errobj->getMessage();
            
$code $errobj->getCode();        }
            
            
$this->raiseError($msg$codePEAR_ERROR_TRIGGERE_USER_ERROR);
    }
    
    
// }}}
    // {{{ addListener()
    
    /**
    * Add an event listener
    *
    * Adds an event listener and returns an ID for it
    *
    * @param        string $event           The ivent name
    * @param        string  $listener       The listener object
    * @return   string
    * @access public
    */
    
function addListener($event, &$listener)
    {
        
$listenerID uniqid('el');
        
$this->eventListeners[$event][$listenerID] =& $listener;
        return 
$listenerID;
    }
    
    
// }}}
    // {{{ removeListener()
    
    /**
    * Removes an event listener
    *
    * Removes the event listener with the given ID
    *
    * @param        string $event           The ivent name
    * @param        string  $listenerID     The listener's ID
    * @return   bool
    * @access public
    */
    
function removeListener($event$listenerID)
    {
        unset(
$this->eventListeners[$event][$listenerID]);
        return 
true;
    }
    
    
// }}}
    // {{{ triggerEvent()
    
    /**
    * Triggers and event an calls the event listeners
    *
    * @param        string $event   The Event that occured
    * @param        object node $node A Reference to the node object which was subject to changes
    * @param        array $eparams  A associative array of params which may be needed by the handler
    * @return   bool
    * @access public
    */
    
function triggerEvent($event, &$node$eparams false)
    {
        if (
$this->skipCallbacks ||
            !isset(
$this->eventListeners[$event]) ||
            !
is_array($this->eventListeners[$event]) ||
            
count($this->eventListeners[$event]) == 0) {
            return 
false;
        }
        
        foreach(
$this->eventListeners[$event] as $key => $val) {
            if (!
method_exists($val'callEvent')) {
                return new 
PEAR_Error($this->_getMessage(NESE_ERROR_NOHANDLER), NESE_ERROR_NOHANDLER);
            }
            
            
$val->callEvent($event$node$eparams);
        }
        
        return 
true;
    }
    
    
// }}}
    // {{{ setAttr()
    
    /**
    * Sets an object attribute
    *
    * @param        array $attr     An associative array with attributes
    *
    * @return   bool
    * @access public
    */
    
function setAttr($attr)
    {
        static 
$hasSetSequence;
        if (!isset(
$hasSetSequence)) {
            
$hasSetSequence false;
        }
        
        if (!
is_array($attr) || count($attr) == 0) {
            return 
false;
        }
        
        foreach (
$attr as $key => $val) {
            
$this->$key $val;
            if (
$key == 'sequence_table') {
                
$hasSetSequence true;
            }
            
            
// only update sequence to reflect new table if they haven't set it manually
            
if (!$hasSetSequence && $key == 'node_table') {
                
$this->sequence_table $this->node_table '_' $this->flparams['id'];
            }
            if(
$key == 'cache' && is_object($val)) {
                
$this->_caching true;
                
$GLOBALS['DB_NestedSet'] = & $this;
            }
        }
        
        return 
true;
    }
    
    
// }}}
    // {{{ setDbOption()
    
    /**
    * Sets a db option.  Example, setting the sequence table format
    *
    * @var string $option The option to set
    * @var string $val The value of the option
    *
    * @access public
    * @return void
    */
    
function setDbOption($option$val)
    {
        
$this->db->setOption($option$val);
    }
    
    
// }}}
    // {{{ testLock()
    
    /**
    * Tests if a database lock is set
    *
    * @access public
    */
    
function testLock()
    {
        
$this->_debugMessage('testLock()');
        if(
$lockID $this->structureTableLock) {
            return 
$lockID;
        }

        
$this->_lockGC();
        
$tb $this->lock_table;
        
$stb $this->node_table;
        
$lockTTL time() - $this->lockTTL;
        
$sql "SELECT lockID FROM $tb WHERE lockTable=" $this->db->quote($stb);
        
$res $this->db->query($sql);
        
$this->_testFatalAbort($res__FILE____LINE__);
        
        if (
$res->numRows()) {
            return new 
PEAR_Error($this->_getMessage(NESE_ERROR_TBLOCKED),NESE_ERROR_TBLOCKED);
        }
        
        return 
false;
    }
    
    
// }}}
    // {{{ _setLock()
    
    /**
    * @access private
    */
    
function _setLock()
    {
        
$lock $this->testLock();
        if(
PEAR::isError($lock)) {
            return 
$lock;
        }
        
        
$this->_debugMessage('_setLock()');
        if(
$this->_caching) {
            @
$this->cache->flush('function_cache');
            
$this->_caching false;
            
$this->_restcache true;
        }
        
$tb $this->lock_table;
        
$stb $this->node_table;
        
$stamp time();
        if (!
$lockID $this->structureTableLock) {
            
$lockID $this->structureTableLock uniqid('lck-');
            
$sql "INSERT INTO $tb SET
                        lockID=" 
$this->db->quote($lockID) . ", 
                        lockTable=" 
$this->db->quote($stb) . ", 
                        lockStamp=" 
$this->db->quote($stamp);
        } else {
            
$sql "UPDATE $tb SET lockStamp=" $this->db->quote($stamp) . "
                    WHERE lockID=" 
$this->db->quote($lockID) . " AND
                        lockTable=" 
$this->db->quote($stb);
        }
        
        
$res $this->db->query($sql);
        
$this->_testFatalAbort($res__FILE____LINE__);
        return 
$lockID;
    }
    
    
// }}}
    // {{{ _releaseLock()
    
    /**
    * @access private
    */
    
function _releaseLock()
    {
        
$this->_debugMessage('_releaseLock()');
        if (!
$lockID $this->structureTableLock) {
            return 
false;
        }
        
        
$tb $this->lock_table;
        
$stb $this->node_table;
        
$sql "DELETE FROM $tb
                WHERE lockTable=" 
$this->db->quote($stb) . " AND 
                    lockID=" 
$this->db->quote($lockID);
        
$res $this->db->query($sql);
        
$this->_testFatalAbort($res__FILE____LINE__);
        
$this->structureTableLock false;
        if(
$this->_restcache) {
            
$this->_caching true;
            
$this->_restcache false;
        }
        return 
true;
    }
    
    
// }}}
    // {{{ _lockGC()
    
    /**
    * @access private
    */
    
function _lockGC()
    {
        
$this->_debugMessage('_lockGC()');
        
$tb $this->lock_table;
        
$stb $this->node_table;
        
$lockTTL time() - $this->lockTTL;
        
$sql "DELETE FROM $tb
                WHERE lockTable=" 
$this->db->quote($stb) . " AND 
                    lockStamp < 
$lockTTL";
        
$res $this->db->query($sql);
        
$this->_testFatalAbort($res__FILE____LINE__);
    }
    
    
// }}}
    // {{{ _values2Query()
    
    /**
    * @access private
    */
    
function _values2Query($values$addval false)
    {
        
$this->_debugMessage('_values2Query($values, $addval = false)');
        if (
is_array($addval)) {
            
$values $values $addval;
        }
        
        
$arq = array();
        foreach(
$values AS $key => $val) {
            
$k trim($key);
            
$v trim($val);
            if (
$k) {
                
                
$arq[] = "$k=" $this->db->quote($v);
            }
        }
        
        if (!
is_array($arq) || count($arq) == 0) {
            return 
false;
        }
        
        
$query implode(', '$arq);
        return 
$query;
    }
    
    
// }}}
    // {{{ _debugMessage()
    
    /**
    * @access private
    */
    
function _debugMessage($msg)
    {
        if (
$this->debug) {
            
$time $this->_getmicrotime();
            echo 
"$time::Debug:: $msg<br />\n";
        }
    }
    
    
// }}}
    // {{{ _getMessage()
    
    /**
    * @access private
    */
    
function _getMessage($code)
    {
        
$this->_debugMessage('_getMessage($code)');
        return isset(
$this->messages[$code]) ? $this->messages[$code] : $this->messages[NESE_MESSAGE_UNKNOWN];
    }
    
    
// }}}
    // {{{ _getmicrotime()
    
    /**
    * @access private
    */
    
function _getmicrotime()
    {
        list(
$usec$sec) = explode(' 'microtime());
        return ((float)
$usec + (float)$sec);
    }
    
    
// }}}

}
// {{{ DB_NestedSet_Node:: class

/**
* Generic class for node objects
*
* @autor Daniel Khan <dk@webcluster.at>;
* @version $Revision: 1.31 $
* @package DB_NestedSet
*
* @access private
*/

// }}}
class DB_NestedSet_Node {
    
// {{{ constructor
    
    /**
    * Constructor
    */
    
function DB_NestedSet_Node($data)
    {
        if (!
is_array($data) || count($data) == 0) {
            return new 
PEAR_ERROR($dataNESE_ERROR_PARAM_MISSING);
        }
        
        
$this->setAttr($data);
        return 
true;
    }
    
    
// }}}
    // {{{ setAttr()
    
    
function setAttr($data)
    {
        if(!
is_array($data) || count($data) == 0) {
            return 
false;
        }
        
        foreach (
$data as $key => $val) {
            
$this->$key $val;
        }
    }
    
    
// }}}
    
}
?>

:: Command execute ::

Enter:
 
Select:
 

:: Search ::
  - regexp 

:: Upload ::
 
[ ok ]

:: Make Dir ::
 
[ ok ]
:: Make File ::
 
[ ok ]

:: Go Dir ::
 
:: Go File ::
 

--[ c99shell v. 1.0 pre-release build #13 powered by Captain Crunch Security Team | http://ccteam.ru | Generation time: 0.0312 ]--