Файл: admin/sources/classes/nodes/classNodes.php
Строк: 684
<?php
/**
* <pre>
* Invision Power Services
* IP.Board v3.3.3
* Very lightweight simple, basic node class
* Owner: Matt Mecham
* Last Updated: $Date: 2012-05-10 16:10:13 -0400 (Thu, 10 May 2012) $
*
* @author $Author: bfarber $
* @copyright (c) 2001 - 2009 Invision Power Services, Inc.
* @license http://www.invisionpower.com/company/standards.php#license
* @package IP.Board
* @link http://www.invisionpower.com
* @since 9th March 2005 11:03
* @version $Revision: 10721 $
*/
class classNodes
{
/**
* Registry object
*
* @access protected
* @var object
*/
protected $registry;
/**
* Database object
*
* @access protected
* @var object
*/
protected $DB;
/**
* Settings object
*
* @access protected
* @var object
*/
protected $settings;
/**
* Request object
*
* @access protected
* @var object
*/
protected $request;
/**
* Language object
*
* @access protected
* @var object
*/
protected $lang;
/**
* Member object
*
* @access protected
* @var object
*/
protected $member;
protected $memberData;
/**
* Cache object
*
* @access protected
* @var object
*/
protected $cache;
protected $caches;
/**
* Item Cache
*
* @access protected
* @var array
*/
protected $_nodeCache = array();
/**
* FIELD: item ID
*
* @access protected
* @var string
*/
protected $_sqlPrimaryID = '';
/**
* FIELD: parent ID
*
* @access protected
* @var string
*/
protected $_sqlParentID = '';
/**
* FIELD: Is folder flag
*
* @access protected
* @var string
*/
protected $_sqlFolderFlag = '';
/**
* FIELD: Item name field
*
* @access protected
* @var string
*/
protected $_sqlTitle = '';
/**
* SQL Field: From
*
* @access protected
* @var string
*/
protected $_sqlTable = '';
/**
* SQL Fields: Additional 'where' information
*
* @access protected
* @var string
*/
protected $_sqlWhere = '';
/**
* SQL Fields: Select information
*
* @access protected
* @var string
*/
protected $_sqlSelect = '*';
/**
* SQL Fields: Node path
*
* @access protected
* @var string
*/
protected $_sqlNodeLevel = '';
/**
* SQL Fields: Node left
*
* @access protected
* @var string
*/
protected $_sqlNodeLeft = '';
/**
* SQL Fields: Node right
*
* @access protected
* @var string
*/
protected $_sqlNodeRight = '';
/**
* SQL Fields: Order field
*
* @access protected
* @var string
*/
protected $_sqlOrder = '';
/**
* SQL Fields: Pass IPB formatted add_join array
*
* @access protected
* @var string
*/
protected $_sqlJoins = '';
/**
* SQL Fields: SQL limit
*
* @access protected
* @var string
*/
protected $_sqlLimit = null;
/**
* SQL Fields: Tbl prefix used when using joins
*
* @access protected
* @var string
*/
protected $_sqlTblPrefix = '';
/**
* Debug cache
* Stores random debug messages and whatnot
*
* @access protected
* @var array
*/
protected $_debugMsgs = array();
/**
* Method constructor
*
* @access public
* @param object Registry Object
* @param array Array of settings:
* [ 'sqlPrimaryID' (the SQL table field for the item ID)
* 'sqlParentID' (the SQL table field for the parent ID)
* 'sqlTitle' (the SQL table field for the item title)
* 'sqlSelect' (the SQL table select fields (* by default))
* 'sqlTable' (the SQL table name)
* 'sqlNodeLevel' (the SQL table field for the node level)
* 'sqlNodeLeft' (the SQL table field for node left)
* 'sqlNodeRight' (the SQL table field for node right)
* 'sqlWhere' (Any additional 'where' information *Optional) ]
* @return @e void
*/
public function __construct()
{
/* Make object */
$this->registry = ipsRegistry::instance();
$this->DB = $this->registry->DB();
$this->settings =& $this->registry->fetchSettings();
$this->request =& $this->registry->fetchRequest();
$this->member = $this->registry->member();
$this->memberData =& $this->registry->member()->fetchMemberData();
$this->cache = $this->registry->cache();
$this->caches =& $this->registry->cache()->fetchCaches();
}
public function init( array $settings )
{
/* Sort out settings */
$this->_sqlPrimaryID = isset( $settings['sqlPrimaryID'] ) ? $settings['sqlPrimaryID'] : '';
$this->_sqlParentID = isset( $settings['sqlParentID'] ) ? $settings['sqlParentID'] : '';
$this->_sqlNodeLevel = isset( $settings['sqlNodeLevel'] ) ? $settings['sqlNodeLevel'] : '';
$this->_sqlNodeRight = isset( $settings['sqlNodeRight'] ) ? $settings['sqlNodeRight'] : '';
$this->_sqlNodeLeft = isset( $settings['sqlNodeLeft'] ) ? $settings['sqlNodeLeft'] : '';
$this->_sqlOrder = isset( $settings['sqlOrder'] ) ? $settings['sqlOrder'] : '';
$this->_sqlTitle = isset( $settings['sqlTitle'] ) ? $settings['sqlTitle'] : '';
$this->_sqlTable = isset( $settings['sqlTable'] ) ? $settings['sqlTable'] : '';
$this->_sqlWhere = isset( $settings['sqlWhere'] ) ? $settings['sqlWhere'] : '';
$this->_sqlSelect = isset( $settings['sqlSelect'] ) ? $settings['sqlSelect'] : $this->_sqlPrimaryID . ', ' . $this->_sqlParentID . ',' . $this->_sqlTitle . ',' . $this->_sqlNodeLeft . ',' . $this->_sqlOrder . ',' . $this->_sqlNodeLevel . ',' . $this->_sqlNodeRight;
$this->_sqlJoins = isset( $settings['sqlJoins'] ) ? $settings['sqlJoins'] : array();
$this->_sqlTblPrefix = isset( $settings['sqlTblPrefix'] ) ? $settings['sqlTblPrefix'] : 'xyxy';
$this->_sqlLimit = isset( $settings['sqlLimit'] ) ? $settings['sqlLimit'] : null;
}
/**
* Allow set/get data
*
*/
public function __call( $method, $arguments )
{
$firstBit = substr( $method, 0, 3 );
$theRest = substr( $method, 3 );
if ( $firstBit == 'set' )
{
switch( $theRest )
{
case 'Order':
$this->_sqlOrder = $arguments[0];
break;
case 'Where':
$this->_sqlWhere = $arguments[0];
break;
case 'Select':
$this->_sqlSelect = $arguments[0];
break;
case 'Limit':
$this->_sqlLimit = $arguments[0];
break;
case 'Joins':
$this->_sqlJoins = $arguments[0];
break;
case 'TblPrefix':
$this->_sqlTblPrefix = $arguments[0];
break;
}
}
else if ( $firstBit == 'get' )
{
switch( $theRest )
{
case 'Order':
return $this->_sqlOrder;
break;
case 'Where':
return $this->_sqlWhere;
break;
case 'Select':
return $this->_sqlSelect;
break;
case 'Limit':
return $this->_sqlLimit;
break;
case 'Joins':
return $this->_sqlJoins;
break;
case 'TblPrefix':
return $this->_sqlTblPrefix;
break;
}
}
else
{
trigger_error( "Call to undefined function " . $method . " in classNodes.php" );
}
}
/**
* Fetches a single node's content
*
* @access public
* @param int
* @return array
*/
public function fetchNodeContent( $nodeId )
{
$fetch = ( is_numeric( $nodeId ) ) ? '=' . intval( $nodeId ) : ' IN (' . implode( ',', IPSLib::cleanIntArray( (array) $nodeId ) ) . ')';
$gotCache = array();
if ( ! is_numeric( $nodeId ) )
{
foreach( $nodeId as $id )
{
if ( isset( $this->_nodeCache[ $id ] ) )
{
$gotCache[ $id ] = $this->_nodeCache[ $id ];
}
}
if ( count( $gotCache ) == count( $nodeId ) )
{
return $gotCache;
}
else
{
$gotCache = array();
}
}
else
{
if ( isset( $this->_nodeCache[ $nodeId ] ) )
{
return $this->_nodeCache[ $nodeId ];
}
}
/* Still here? */
if ( is_numeric( $nodeId ) OR ! count( $gotCache ) )
{
if ( is_array( $this->_sqlJoins ) and count( $this->_sqlJoins ) )
{
$this->DB->build( array( 'select' => $this->_sqlTblPrefix . '.' . $this->_sqlSelect,
'from' => array( $this->_sqlTable => $this->_sqlTblPrefix ),
'where' => $this->_sqlTblPrefix . '.' . $this->_sqlPrimaryID . $fetch,
'add_join' => $this->_sqlJoins ) );
}
else
{
$this->DB->build( array( 'select' => $this->_sqlSelect,
'from' => $this->_sqlTable,
'where' => $this->_sqlPrimaryID . $fetch ) );
}
$o = $this->DB->execute();
while( $row = $this->DB->fetch( $o ) )
{
$return[ $row[ $this->_sqlPrimaryID ] ] = $row;
$this->_nodeCache[ $row[ $this->_sqlPrimaryID ] ] = $row;
}
}
return ( is_numeric( $nodeId ) ) ? $this->_nodeCache[ $nodeId ] : $return;
}
/**
* Fetches left/right/level data
*
* @access public
* @param int
* @return array - left, right, level
*/
public function fetchNodeInfo( $nodeId )
{
/* If this is ID 0... */
if ( $nodeId == 0 )
{
$left = $this->DB->buildAndFetch( array( 'select' => 'MIN(' . $this->_sqlNodeLeft . ') as nleft',
'from' => $this->_sqlTable,
'where' => $this->_sqlNodeLevel . '=0' ) );
$right = $this->DB->buildAndFetch( array( 'select' => 'MAX(' . $this->_sqlNodeRight . ') as nright',
'from' => $this->_sqlTable,
'where' => $this->_sqlNodeLevel . '=0' ) );
return array( $left['nleft'], $right['nright'], 0 );
}
else
{
$data = $this->fetchNodeContent( $nodeId );
return array( $data[ $this->_sqlNodeLeft ],
$data[ $this->_sqlNodeRight ],
$data[ $this->_sqlNodeLevel ] );
}
}
/**
* Fetches parent info
*
* @access public
* @param int Node id
* @param string Where data
* @return DB row
*/
public function fetchParentInfo( $nodeId, $where = '')
{
/* Init where */
$where = ( $where ) ? $where : $this->_sqlWhere;
/* Fetch noded data */
$nodeData = $this->fetchNodeInfo( $nodeId );
if ( count( $nodeData ) )
{
return false;
}
/* Lets go */
list( $leftId, $rightId, $level ) = $nodeData;
/* Jump up a level */
$level--;
$where = ( $where ) ? ' AND (' . $where . ')' : '';
/* Fetch data */
if ( is_array( $this->_sqlJoins ) and count( $this->_sqlJoins ) )
{
$this->DB->build( array( 'select' => $this->_sqlTblPrefix . '.' . $this->_sqlSelect,
'from' => array( $this->_sqlTable => $this->_sqlTblPrefix ),
'where' => $this->_sqlTblPrefix . '.' . $this->_sqlNodeLeft . ' < ' . $leftId .
' AND ' . $this->_sqlTblPrefix . '.' . $this->_sqlNodeLeft . ' > ' . $rightId .
' AND ' . $this->_sqlTblPrefix . '.' . $this->_sqlNodeLevel . ' = ' . $level .
$where,
'order' => $this->_sqlTblPrefix . '.' . $this->_sqlNodeLeft,
'add_join' => $this->_sqlJoins ) );
}
else
{
$this->DB->build( array( 'select' => $this->_sqlSelect,
'from' => $this->_sqlTable,
'where' => $this->_sqlNodeLeft . ' < ' . $leftId .
' AND ' . $this->_sqlNodeLeft . ' > ' . $rightId .
' AND ' . $this->_sqlNodeLevel . ' = ' . $level .
$where,
'order' => $this->_sqlNodeLeft ) );
}
$o = $this->DB->execute();
$this->_nodeCache[ $nodeId ] = $row = $this->DB->fetch( $o );
return ( count( $row ) ) ? $row : false;
}
/**
* Returns DB resource to all nodes
*
* @access public
* @param string Where string
* @return boolean
*/
public function fetchTree( $where='' )
{
/* Init where */
$where = ( $where ) ? $where : $this->_sqlWhere;
/* Fetch data */
if ( is_array( $this->_sqlJoins ) and count( $this->_sqlJoins ) OR ! empty( $this->_sqlTblPrefix ) )
{
$_order = $this->getOrder();
$order = ( ! empty( $_order ) ) ? $_order : $this->_sqlTblPrefix . '.' . $this->_sqlNodeLeft;
$this->DB->build( array( 'select' => $this->_sqlTblPrefix . '.' . $this->_sqlSelect,
'from' => array( $this->_sqlTable => $this->_sqlTblPrefix ),
'where' => $where,
'limit' => $this->getLimit(),
'order' => $order,
'add_join' => $this->_sqlJoins ) );
}
else
{
$_order = $this->getOrder();
$order = ( ! empty( $_order ) ) ? $_order : $this->_sqlNodeLeft;
$this->DB->build( array( 'select' => $this->_sqlSelect,
'from' => $this->_sqlTable,
'where' => $where,
'limit' => $this->getLimit(),
'order' => $order ) );
}
/* Set up handler */
$this->_dbHandle = $this->DB->execute();
return true;
}
/**
* Fetch the branch starting with $nodeId
*
* @access public
* @param int Node Id
* @param string Where clause
* @return boolean
*/
public function fetchBranch( $nodeId, $inWhere='' )
{
/* Init where */
$inWhere = ( $inWhere ) ? $inWhere : $this->_sqlWhere;
/* Set up tbl prefix */
$a = ( is_array( $this->_sqlJoins ) and count( $this->_sqlJoins ) ) ? $this->_sqlTblPrefix : 'aaa';
/* Set up select */
$select = $a . '.' . $this->_sqlSelect;
$where = 'bbb.' . $this->_sqlPrimaryID . '=' . $nodeId . ' AND ' . $a . '.' . $this->_sqlNodeLeft . ' >= bbb.' . $this->_sqlNodeLeft . ' AND ' . $a . '.' . $this->_sqlNodeRight . ' <= bbb.' . $this->_sqlNodeRight;
/* Custom where? */
$where .= ( $inWhere ) ? ' AND (' . $inWhere . ')' : '';
$_joins = $this->_sqlJoins;
$_joins[] = array( 'from' => array( $this->_sqlTable => 'bbb' ),
'type' => 'inner' );
$this->DB->build( array( 'select' => $select,
'from' => array( $this->_sqlTable => $a ),
'where' => $where,
'order' => $a . '.' . $this->_sqlNodeLeft,
'add_join' => $_joins ) );
/* Set up handler */
$this->_dbHandle = $this->DB->execute();
return true;
}
/**
* Fetch the parents of $nodeId
*
* @access public
* @param int Node Id
* @param string Where clause
* @return boolean
*/
public function fetchParents( $nodeId, $inWhere='' )
{
/* Init where */
$inWhere = ( $inWhere ) ? $inWhere : $this->_sqlWhere;
/* Set up tbl prefix */
$a = ( is_array( $this->_sqlJoins ) and count( $this->_sqlJoins ) ) ? $this->_sqlTblPrefix : 'aaa';
/* Set up select */
$select = $a . '.' . $this->_sqlSelect;
$where = 'bbb.' . $this->_sqlPrimaryID . '=' . $nodeId . ' AND bbb.' . $this->_sqlNodeLeft . ' BETWEEN ' . $a . '.' . $this->_sqlNodeLeft . ' AND ' . $a . '.' . $this->_sqlNodeRight;
/* Custom where? */
$where .= ( $inWhere ) ? ' AND (' . $inWhere . ')' : '';
$_joins = $this->_sqlJoins;
$_joins[] = array( 'from' => array( $this->_sqlTable => 'bbb' ),
'type' => 'inner' );
$this->DB->build( array( 'select' => $select,
'from' => array( $this->_sqlTable => $a ),
'where' => $where,
'order' => $a . '.' . $this->_sqlNodeLeft,
'add_join' => $_joins ) );
/* Set up handler */
$this->_dbHandle = $this->DB->execute();
return true;
}
/**
* Fetch the children of $nodeId
*
* @access public
* @param int Node Id
* @param string Where clause
* @return boolean
*/
public function fetchChildren( $nodeId, $inWhere='' )
{
/* Init where */
$inWhere = ( $inWhere ) ? $inWhere : $this->_sqlWhere;
/* Set up tbl prefix */
$a = ( is_array( $this->_sqlJoins ) and count( $this->_sqlJoins ) ) ? $this->_sqlTblPrefix : 'aaa';
/* Set up select */
$select = $a . '.' . $this->_sqlSelect;
if ( $nodeId == 0 )
{
$where = '(1=1)';
}
else
{
$where = 'bbb.' . $this->_sqlPrimaryID . '=' . $nodeId . ' AND ' . $a . '.' . $this->_sqlNodeLeft . ' > ' . 'bbb.' . $this->_sqlNodeLeft . ' AND ' . $a . '.' . $this->_sqlNodeRight . ' < bbb.' . $this->_sqlNodeRight;
}
/* Custom where? */
$where .= ( $inWhere ) ? ' AND (' . $inWhere . ')' : '';
$_joins = $this->_sqlJoins;
if ( $nodeId > 0 )
{
$_joins[] = array( 'from' => array( $this->_sqlTable => 'bbb' ),
'type' => 'inner' );
}
$this->DB->build( array( 'select' => $select,
'from' => array( $this->_sqlTable => $a ),
'where' => $where,
'order' => $a . '.' . $this->_sqlNodeLeft,
'limit' => $this->getLimit(),
'add_join' => $_joins ) );
/* Set up handler */
$this->_dbHandle = $this->DB->execute();
return true;
}
/**
* Returns an item with parents and children
*
* @access public
* @param int Node Id
* @param string Where clause
* @return boolean
*/
public function fetchSlice( $nodeId, $inWhere='' )
{
/* Init where */
$inWhere = ( $inWhere ) ? $inWhere : $this->_sqlWhere;
/* Init */
$i = 0;
/* Set up tbl prefix */
$a = ( is_array( $this->_sqlJoins ) and count( $this->_sqlJoins ) ) ? $this->_sqlTblPrefix : 'aaa';
/* Select */
$select = $a . '.' . $this->_sqlNodeLeft . ', ' . $a . '.' . $this->_sqlNodeRight . ', ' . $a . '.' . $this->_sqlNodeLevel;
$where = 'bbb.' . $this->_sqlPrimaryID . '=' . $nodeId . ' AND bbb.' . $this->_sqlNodeLeft . ' BETWEEN ' . $a . '.' . $this->_sqlNodeLeft . ' AND ' . $a . '.' . $this->_sqlNodeRight;
/* Custom where? */
$where .= ( $inWhere ) ? ' AND (' . $inWhere . ')' : '';
$_joins = $this->_sqlJoins;
$_joins[] = array( 'from' => array( $this->_sqlTable => 'bbb' ),
'type' => 'inner' );
$this->DB->build( array( 'select' => $select,
'from' => array( $this->_sqlTable => $a ),
'where' => $where,
'order' => $a . '.' . $this->_sqlNodeLeft,
'add_join' => $_joins ) );
/* Set up handler */
$this->_dbHandle = $this->DB->execute();
$len = $this->recordCount();
/* Set up tbl prefix */
$a = ( is_array( $this->_sqlJoins ) and count( $this->_sqlJoins ) ) ? $this->_sqlTblPrefix : 'aaa';
$_where = ( $inWhere ) ? ' AND (' . $inWhere . ')' : '';
/* start main where */
$where = '(' . $a . '.' . $this->_sqlNodeLevel . ' =1';
while( $row = $this->DB->fetch( $this->_dbHandle ) )
{
if ( ( ++$i == $len ) && ( $row[ $this->_sqlNodeLeft ] + 1 ) == $row[ $this->_sqlNodeRight ] )
{
break;
}
$where .= ' OR (' . $a .'.'. $this->_sqlNodeLevel . ' = ' . ( $row[$this->_sqlNodeLevel] + 1 )
. ' AND ' . $a .'.'. $this->_sqlNodeLeft . ' > ' . $row[$this->_sqlNodeLeft]
. ' AND ' . $a .'.'. $this->_sqlNodeRight . ' < ' . $row[$this->_sqlNodeRight] . ')';
}
$where .= ")" . $_where;
/* Fetch data */
if ( is_array( $this->_sqlJoins ) and count( $this->_sqlJoins ) )
{
$this->DB->build( array( 'select' => $this->_sqlTblPrefix . '.' . $this->_sqlSelect,
'from' => array( $this->_sqlTable => $this->_sqlTblPrefix ),
'where' => $where,
'order' => $this->_sqlTblPrefix . '.' . $this->_sqlNodeLeft,
'add_join' => $this->_sqlJoins ) );
}
else
{
$this->DB->build( array( 'select' => $a . '.' . $this->_sqlSelect,
'from' => $this->_sqlTable . ' ' . $a,
'where' => $where,
'order' => $a . '.' . $this->_sqlNodeLeft ) );
}
/* Set up handler */
$this->_dbHandle = $this->DB->execute();
return true;
}
/**
* Is descendant of
* Checks to see if a node is a descendant of another node. Simple really
* @param array node (descendant)
* @param array node (root parent)
*/
public function isDescendantOf( $desc, $parent )
{
if ( ! isset( $desc[ $this->_sqlNodeLeft ] ) && ! isset( $desc[ $this->_sqlNodeRight ] ) )
{
return false;
}
if ( ! isset( $parent[ $this->_sqlNodeLeft ] ) && ! isset( $parent[ $this->_sqlNodeRight ] ) )
{
return false;
}
if ( $desc[ $this->_sqlNodeLeft ] > $parent[ $this->_sqlNodeLeft ] && $desc[ $this->_sqlNodeLeft ] < $parent[ $this->_sqlNodeRight ] )
{
return true;
}
else
{
return false;
}
}
/**
* Add node
*
* @param int Parent Node ID
* @param array Array of fields to insert
* @return int Insert ID
*/
public function addNode( $parentId, $data )
{
$nInfo = $this->fetchNodeInfo( $parentId );
if ( ! isset( $nInfo[0] ) OR empty( $parentId ) )
{
/* Add without parents? */
if ( empty( $parentId ) )
{
/* Find the highest right value */
$right = $this->DB->buildAndFetch( array( 'select' => '*',
'from' => $this->_sqlTable,
'order' => $this->_sqlNodeRight . ' DESC',
'limit' => array( 0, 1 ) ) );
$leftId = $right[ $this->_sqlNodeRight ] + 1;
$rightId = $right[ $this->_sqlNodeRight ] + 2;
$level = 0;
$data[ $this->_sqlNodeLeft ] = $leftId;
$data[ $this->_sqlNodeRight ] = $rightId;
$data[ $this->_sqlNodeLevel ] = $level;
}
else
{
return false;
}
}
else
{
list( $leftId, $rightId, $level ) = $nInfo;
$data[ $this->_sqlNodeLeft ] = $rightId;
$data[ $this->_sqlNodeRight ] = ( $rightId + 1 );
$data[ $this->_sqlNodeLevel ] = ( $level + 1 );
/* Set data: Shift over the elements */
$set = $this->_sqlNodeLeft . ' = CASE WHEN ' . $this->_sqlNodeLeft . '>' . $rightId . ' THEN ' . $this->_sqlNodeLeft . '+2 ELSE ' . $this->_sqlNodeLeft . ' END, '
. $this->_sqlNodeRight . ' = CASE WHEN ' . $this->_sqlNodeRight . '>=' . $rightId . ' THEN ' . $this->_sqlNodeRight . '+2 ELSE ' . $this->_sqlNodeRight . ' END ';
/* Pre formatted */
$this->DB->update( $this->_sqlTable, $set, $this->_sqlNodeRight . '>=' . $rightId, false, true );
}
/* Insert new row */
$this->DB->insert( $this->_sqlTable, $data );
return $this->DB->getInsertId();
}
/**
* Move and node and all children to a new parent node
*
* @param int Node ID
* @param int New parent ID
* @return int Insert ID
*/
public function moveNode( $nodeId, $newParentId )
{
$nInfo = $this->fetchNodeInfo( $nodeId );
if ( ! isset( $nInfo[0] ) )
{
return false;
}
list( $leftId, $rightId, $level ) = $nInfo;
$nInfo = $this->fetchNodeInfo( $newParentId );
if ( ! isset( $nInfo[0] ) )
{
return false;
}
list( $leftIdP, $rightIdP, $levelP ) = $nInfo;
/* Make sure it can't be moved into itself or into an invalid node */
if ( $nodeId == $newParentId || $leftId == $leftIdP || ( $leftIdP >= $leftId && $leftIdP <= $rightId ) || ( $newParentId > 0 && $level == $levelP + 1 && $leftId > $leftIdP && $rightId < $rightIdP ) )
{
return false;
}
if ( $newParentId == 0 )
{
/* set the math right */
$levelP = -1;
$set = $this->_sqlNodeLevel . ' = CASE WHEN ' . $this->_sqlNodeLeft . ' BETWEEN ' . $leftId . ' AND ' . $rightId . ' THEN ' . $this->_sqlNodeLevel . sprintf( '%+d', - ( $level - 1 ) + $levelP ) . ' ELSE ' . $this->_sqlNodeLevel . ' END, '
. $this->_sqlNodeLeft . ' = CASE WHEN ' . $this->_sqlNodeLeft . ' BETWEEN ' . $rightId . ' AND ' . $rightIdP . ' THEN ' . $this->_sqlNodeLeft . '-' . ( $rightId - $leftId + 1 ) . ' '
. 'WHEN ' . $this->_sqlNodeLeft . ' BETWEEN ' . $leftId . ' AND ' . $rightId . ' THEN ' . $this->_sqlNodeLeft . '+' . ( $rightIdP - $rightId ) . ' ELSE ' . $this->_sqlNodeLeft . ' END, '
. $this->_sqlNodeRight . ' = CASE WHEN ' . $this->_sqlNodeRight . ' BETWEEN ' . ( $rightId + 1 ) . ' AND ' . ( $rightIdP ) . ' THEN ' . $this->_sqlNodeRight . '-' . ( $rightId - $leftId + 1 ) . ' '
. 'WHEN ' . $this->_sqlNodeRight . ' BETWEEN ' . $leftId . ' AND ' . $rightId . ' THEN ' . $this->_sqlNodeRight . '+' . ( $rightIdP - $rightId ) . ' ELSE ' . $this->_sqlNodeRight . ' END ';
$whr = '(' . $this->_sqlNodeLeft . ' BETWEEN ' . $leftId . ' AND ' . $rightIdP . ' ' . 'OR ' . $this->_sqlNodeRight . ' BETWEEN ' . $leftId . ' AND ' . $rightIdP . ')';
}
else if ( $leftIdP < $leftId && $rightIdP > $rightId && ( $levelP < $level - 1 ) )
{
$set = $this->_sqlNodeLevel . ' = CASE WHEN ' . $this->_sqlNodeLeft . ' BETWEEN ' . $leftId . ' AND ' . $rightId . ' THEN ' . $this->_sqlNodeLevel . sprintf('%+d', - ( $level - 1) + $levelP ) . ' ELSE ' . $this->_sqlNodeLevel . ' END, '
. $this->_sqlNodeRight . ' = CASE WHEN ' . $this->_sqlNodeRight . ' BETWEEN ' . ( $rightId + 1 ) . ' AND ' . ( $rightIdP - 1 ) . ' THEN ' . $this->_sqlNodeRight . '-' . ( $rightId - $leftId + 1) . ' '
. 'WHEN ' . $this->_sqlNodeLeft . ' BETWEEN ' . $leftId . ' AND ' . $rightId . ' THEN ' . $this->_sqlNodeRight . '+' . ( ( ( $rightIdP - $rightId - $level + $levelP ) / 2 ) * 2 + $level - $levelP - 1 ) . ' ELSE ' . $this->_sqlNodeRight . ' END, '
. $this->_sqlNodeLeft . ' = CASE WHEN ' . $this->_sqlNodeLeft . ' BETWEEN ' . ( $rightId + 1 ) . ' AND ' . ( $rightIdP - 1 ) . ' THEN ' . $this->_sqlNodeLeft . '-' . ( $rightId - $leftId + 1 ) . ' '
. 'WHEN ' . $this->_sqlNodeLeft . ' BETWEEN ' . $leftId . ' AND ' . $rightId . ' THEN ' . $this->_sqlNodeLeft . '+' . ( ( ( $rightIdP - $rightId - $level + $levelP ) / 2 ) * 2 + $level - $levelP - 1 ) . ' ELSE ' . $this->_sqlNodeLeft . ' END ';
$whr = $this->_sqlNodeLeft . ' BETWEEN ' . ( $leftIdP + 1 ) . ' AND ' . ( $rightIdP - 1 );
}
else if ( $leftIdP < $leftId )
{
$set = $this->_sqlNodeLevel . ' = CASE WHEN ' . $this->_sqlNodeLeft . ' BETWEEN ' . $leftId . ' AND ' . $rightId . ' THEN ' . $this->_sqlNodeLevel . sprintf( '%+d', - ( $level - 1 ) + $levelP ) . ' ELSE ' . $this->_sqlNodeLevel . ' END, '
. $this->_sqlNodeLeft . ' = CASE WHEN ' . $this->_sqlNodeLeft . ' BETWEEN ' . $rightIdP . ' AND ' . ( $leftId - 1 ) . ' THEN ' . $this->_sqlNodeLeft . '+' . ( $rightId - $leftId + 1 ) . ' '
. 'WHEN ' . $this->_sqlNodeLeft . ' BETWEEN ' . $leftId . ' AND ' . $rightId . ' THEN ' . $this->_sqlNodeLeft . '-' . ( $leftId - $rightIdP ) . ' ELSE ' . $this->_sqlNodeLeft . ' END, '
. $this->_sqlNodeRight . ' = CASE WHEN ' . $this->_sqlNodeRight . ' BETWEEN ' . $rightIdP . ' AND ' . $leftId . ' THEN ' . $this->_sqlNodeRight . '+' . ( $rightId - $leftId + 1) . ' '
. 'WHEN ' . $this->_sqlNodeRight . ' BETWEEN ' . $leftId . ' AND ' . $rightId . ' THEN ' . $this->_sqlNodeRight . '-' . ( $leftId - $rightIdP ) . ' ELSE ' . $this->_sqlNodeRight . ' END ';
$whr = '(' . $this->_sqlNodeLeft . ' BETWEEN ' . $leftIdP . ' AND ' . $rightId. ' ' . 'OR ' . $this->_sqlNodeRight . ' BETWEEN ' . $leftIdP . ' AND ' . $rightId . ')';
}
else
{
$set = $this->_sqlNodeLevel . ' = CASE WHEN ' . $this->_sqlNodeLeft . ' BETWEEN ' . $leftId . ' AND ' . $rightId . ' THEN ' . $this->_sqlNodeLevel . sprintf( '%+d', - ( $level - 1 ) + $levelP ) . ' ELSE ' . $this->_sqlNodeLevel . ' END, '
. $this->_sqlNodeLeft . ' = CASE WHEN ' . $this->_sqlNodeLeft . ' BETWEEN ' . $rightId . ' AND ' . $rightIdP . ' THEN ' . $this->_sqlNodeLeft . '-' . ( $rightId - $leftId + 1 ) . ' '
. 'WHEN ' . $this->_sqlNodeLeft . ' BETWEEN ' . $leftId . ' AND ' . $rightId . ' THEN ' . $this->_sqlNodeLeft . '+' . ( $rightIdP - 1 - $rightId ) . ' ELSE ' . $this->_sqlNodeLeft . ' END, '
. $this->_sqlNodeRight . ' = CASE WHEN ' . $this->_sqlNodeRight . ' BETWEEN ' . ( $rightId + 1 ) . ' AND ' . ( $rightIdP - 1 ) . ' THEN ' . $this->_sqlNodeRight . '-' . ( $rightId - $leftId + 1 ) . ' '
. 'WHEN ' . $this->_sqlNodeRight . ' BETWEEN ' . $leftId . ' AND ' . $rightId . ' THEN ' . $this->_sqlNodeRight . '+' . ( $rightIdP - 1 - $rightId ) . ' ELSE ' . $this->_sqlNodeRight . ' END ';
$whr = '(' . $this->_sqlNodeLeft . ' BETWEEN ' . $leftId . ' AND ' . $rightIdP . ' ' . 'OR ' . $this->_sqlNodeRight . ' BETWEEN ' . $leftId . ' AND ' . $rightIdP . ')';
}
//print "<pre>";
//print wordwrap( $set, 100, '<br />' );
//print "n" . wordwrap( $whr, 100, '<br />' );
//exit();
/* Pre formatted */
$this->DB->update( $this->_sqlTable, $set, $whr, false, true );
return true;
}
/**
* Delete a node. Any children are moved to root.
*
* @param int Node ID
* @return boolean
*/
public function deleteNode( $nodeId )
{
$nInfo = $this->fetchNodeInfo( $nodeId );
if ( ! isset( $nInfo[0] ) )
{
return false;
}
list( $leftId, $rightId, $level ) = $nInfo;
/* Delete from DB */
$this->DB->delete( $this->_sqlTable, $this->_sqlPrimaryID . '=' . intval( $nodeId ) );
/* Move other nodes down */
$set = $this->_sqlNodeLevel . ' = CASE WHEN ' . $this->_sqlNodeLeft . ' BETWEEN ' . $leftId . ' AND ' . $rightId . ' THEN ' . $this->_sqlNodeLevel . ' - 1 ELSE ' . $this->_sqlNodeLevel . ' END, '
. $this->_sqlNodeRight . ' = CASE WHEN ' . $this->_sqlNodeRight . ' BETWEEN ' . $leftId . ' AND ' . $rightId . ' THEN ' . $this->_sqlNodeRight . ' - 1 '
. 'WHEN ' . $this->_sqlNodeRight . ' > ' . $rightId . ' THEN ' . $this->_sqlNodeRight . ' - 2 ELSE ' . $this->_sqlNodeRight . ' END, '
. $this->_sqlNodeLeft . ' = CASE WHEN ' . $this->_sqlNodeLeft . ' BETWEEN ' . $leftId . ' AND ' . $rightId . ' THEN ' . $this->_sqlNodeLeft . ' - 1 '
. 'WHEN ' . $this->_sqlNodeLeft . ' > ' . $rightId . ' THEN ' . $this->_sqlNodeLeft . ' - 2 ELSE ' . $this->_sqlNodeLeft . ' END ';
$whr = $this->_sqlNodeRight . ' > ' . $leftId;
/* Pre formatted */
$this->DB->update( $this->_sqlTable, $set, $whr, false, true );
return true;
}
/**
* Delete a node branch (node + children)
*
* @param int Node ID
* @return boolean
*/
public function deleteBranch( $nodeId )
{
$nInfo = $this->fetchNodeInfo( $nodeId );
if ( ! isset( $nInfo[0] ) )
{
return false;
}
list( $leftId, $rightId, $level ) = $nInfo;
/* Delete from DB */
$this->DB->delete( $this->_sqlTable, $this->_sqlNodeLeft . ' BETWEEN ' . $leftId . ' AND ' . $rightId );
/* Fix position */
$deltaId = ( ( $rightId - $leftId ) + 1 );
$set = $this->_sqlNodeLeft . ' = CASE WHEN ' . $this->_sqlNodeLeft . ' > ' . $leftId.' THEN ' . $this->_sqlNodeLeft . ' - ' . $deltaId . ' ELSE ' . $this->_sqlNodeLeft . ' END, '
. $this->_sqlNodeRight . ' = CASE WHEN ' . $this->_sqlNodeRight . ' > ' . $leftId . ' THEN ' . $this->_sqlNodeRight . ' - ' . $deltaId . ' ELSE ' . $this->_sqlNodeRight . ' END ';
$whr = $this->_sqlNodeRight . ' > ' . $rightId;
/* Pre formatted */
$this->DB->update( $this->_sqlTable, $set, $whr, false, true );
return true;
}
/**
* Switch a node's position within it's level
*
* @access public
* @param int ID1
* @param int ID 2
* @param string position (before/after)
* @return boolean
*/
public function movePosition( $id1, $id2, $position='after')
{
$nInfo = $this->fetchNodeInfo( $id1 );
if ( ! isset( $nInfo[0] ) )
{
return false;
}
list( $leftId1, $rightId1, $level1 ) = $nInfo;
$nInfo = $this->fetchNodeInfo( $id2 );
if ( ! isset( $nInfo[0] ) )
{
return false;
}
list( $leftId2, $rightId2, $level2 ) = $nInfo;
/* On the level? */
if ( $level1 != $level2 )
{
return false;
}
/* Before? */
if ( $position == 'before' )
{
if ( $leftId1 > $leftId2 )
{
$set = $this->_sqlNodeRight . ' = CASE WHEN ' . $this->_sqlNodeLeft . ' BETWEEN ' . $leftId1 . ' AND ' . $rightId1 . ' THEN ' . $this->_sqlNodeRight . ' - ' . ($leftId1 - $leftId2) . ' '
. 'WHEN ' . $this->_sqlNodeLeft . ' BETWEEN ' . $leftId2 . ' AND ' . ($leftId1 - 1) . ' THEN ' . $this->_sqlNodeRight . ' + ' . ( $rightId1 - $leftId1 + 1 ) . ' ELSE ' . $this->_sqlNodeRight . ' END, '
. $this->_sqlNodeLeft . ' = CASE WHEN ' . $this->_sqlNodeLeft . ' BETWEEN ' . $leftId1 . ' AND ' . $rightId1 . ' THEN ' . $this->_sqlNodeLeft . ' - ' . ($leftId1 - $leftId2) . ' '
. 'WHEN ' . $this->_sqlNodeLeft . ' BETWEEN ' . $leftId2 . ' AND ' . ($leftId1 - 1) . ' THEN ' . $this->_sqlNodeLeft . ' + ' . ( $rightId1 - $leftId1 + 1 ) . ' ELSE ' . $this->_sqlNodeLeft . ' END ';
$whr = $this->_sqlNodeLeft . ' BETWEEN ' . $leftId2 . ' AND ' . $rightId1;
}
else
{
$set = $this->_sqlNodeRight . ' = CASE WHEN ' . $this->_sqlNodeLeft . ' BETWEEN ' . $leftId1 . ' AND ' . $rightId1 . ' THEN ' . $this->_sqlNodeRight . ' + ' . ( ( $leftId2 - $leftId1 ) - ( $rightId1 - $leftId1 + 1 ) ) . ' '
. 'WHEN ' . $this->_sqlNodeLeft . ' BETWEEN ' . ( $rightId1 + 1 ) . ' AND ' . ($leftId2 - 1) . ' THEN ' . $this->_sqlNodeRight . ' - ' . ( ( $rightId1 - $leftId1 + 1 ) ) . ' ELSE ' . $this->_sqlNodeRight . ' END, '
. $this->_sqlNodeLeft . ' = CASE WHEN ' . $this->_sqlNodeLeft . ' BETWEEN ' . $leftId1 . ' AND ' . $rightId1 . ' THEN ' . $this->_sqlNodeLeft . ' + ' . ( ( $leftId2 - $leftId1 ) - ( $rightId1 - $leftId1 + 1 ) ) . ' '
. 'WHEN ' . $this->_sqlNodeLeft . ' BETWEEN ' . ( $rightId1 + 1 ) . ' AND ' . ($leftId2 - 1) . ' THEN ' . $this->_sqlNodeLeft . ' - ' . ( $rightId1 - $leftId1 + 1 ) . ' ELSE ' . $this->_sqlNodeLeft . ' END ';
$whr = $this->_sqlNodeLeft . ' BETWEEN ' . $leftId1 . ' AND ' . ($leftId2 - 1);
}
}
if ( $position == 'after' )
{
if ( $leftId1 > $leftId2 )
{
$set = $this->_sqlNodeRight . ' = CASE WHEN ' . $this->_sqlNodeLeft . ' BETWEEN ' . $leftId1 . ' AND ' . $rightId1 . ' THEN ' . $this->_sqlNodeRight . ' - ' . ( $leftId1 - $leftId2 - ( $rightId2 - $leftId2 + 1 ) ) . ' '
. 'WHEN ' . $this->_sqlNodeLeft . ' BETWEEN ' . ( $rightId2 + 1 ) . ' AND ' . ( $leftId1 - 1 ) . ' THEN ' . $this->_sqlNodeRight . ' + ' . ( $rightId1 - $leftId1 + 1) . ' ELSE ' . $this->_sqlNodeRight . ' END, '
. $this->_sqlNodeLeft . ' = CASE WHEN ' . $this->_sqlNodeLeft . ' BETWEEN ' . $leftId1 . ' AND ' . $rightId1 . ' THEN ' . $this->_sqlNodeLeft . ' - ' . ($leftId1 - $leftId2 - ( $rightId2 - $leftId2 + 1 ) ) . ' '
. 'WHEN ' . $this->_sqlNodeLeft . ' BETWEEN ' . ( $rightId2 + 1 ) . ' AND ' . ( $leftId1 - 1 ) . ' THEN ' . $this->_sqlNodeLeft . ' + ' . ( $rightId1 - $leftId1 + 1) . ' ELSE ' . $this->_sqlNodeLeft . ' END ';
$whr = $this->_sqlNodeLeft . ' BETWEEN ' . ($rightId2 + 1) . ' AND ' . $rightId1;
}
else
{
$set = $this->_sqlNodeRight . ' = CASE WHEN ' . $this->_sqlNodeLeft . ' BETWEEN ' . $leftId1 . ' AND ' . $rightId1 . ' THEN ' . $this->_sqlNodeRight . ' + ' . ($rightId2 - $rightId1) . ' '
. 'WHEN ' . $this->_sqlNodeLeft . ' BETWEEN ' . ( $rightId1 + 1 ) . ' AND ' . $rightId2 . ' THEN ' . $this->_sqlNodeRight . ' - ' . ( ( $rightId1 - $leftId1 + 1 ) ) . ' ELSE ' . $this->_sqlNodeRight . ' END, '
. $this->_sqlNodeLeft . ' = CASE WHEN ' . $this->_sqlNodeLeft . ' BETWEEN ' . $leftId1 . ' AND ' . $rightId1 . ' THEN ' . $this->_sqlNodeLeft . ' + ' . ($rightId2 - $rightId1) . ' '
. 'WHEN ' . $this->_sqlNodeLeft . ' BETWEEN ' . ( $rightId1 + 1 ) . ' AND ' . $rightId2 . ' THEN ' . $this->_sqlNodeLeft . ' - ' . ( $rightId1 - $leftId1 + 1 ) . ' ELSE ' . $this->_sqlNodeLeft . ' END ';
$where = $this->_sqlNodeLeft . ' BETWEEN ' . $leftId1 . ' AND ' . $rightId2;
}
}
/* Pre formatted */
$this->DB->update( $this->_sqlTable, $set, $whr, false, true );
return true;
}
/**
* Returns record count
*
* @return int
*/
public function recordCount()
{
return $this->DB->getTotalRows( $this->_dbHandle );
}
/**
* Returns the current row.
*
* @return array
*/
public function nextRow()
{
return $this->DB->fetch( $this->_dbHandle );
}
/**
* Rebuild the tree
*
* @access public
* @param int Root ID
* @param int Left value
* @param int Depth
* @return nothing
*/
function rebuildTree( $root=0, $left=1, $depth=-1 )
{
$right = $left + 1;
$nDepth = $depth + 1;
$this->DB->build( array( 'select' => '*',
'from' => $this->_sqlTable,
'where' => $this->_sqlParentID . '=' . intval( $root ),
'order' => $this->_sqlOrder ) );
$o = $this->DB->execute();
while( $row = $this->DB->fetch( $o ) )
{
$right = $this->rebuildTree( $row[ $this->_sqlPrimaryID ], $right, $nDepth );
}
$this->DB->update( $this->_sqlTable, array( $this->_sqlNodeLeft => $left,
$this->_sqlNodeRight => $right,
$this->_sqlNodeLevel => $depth ), $this->_sqlPrimaryID . '=' . $root );
return $right + 1;
}
/**
* Drop the node cache
*
*/
public function dropCache()
{
$this->_nodeCache = array();
}
/**
* Show the entire tree as HITMUHL
*
* @access public
*/
public function debugShowTree()
{
/* Init */
$content = '';
/* reset params */
$this->setOrder(null);
$this->setWhere(null);
/* Load entire tree */
$this->fetchTree();
while( $item = $this->nextRow() )
{
$content .= str_repeat( ' ', 6 * $item[ $this->_sqlNodeLevel ] ) . '(' . $item[ $this->_sqlPrimaryID ] . ')<strong>' . $item[ $this->_sqlTitle ] . '</strong><br />';
}
return $content;
}
}
/**
* Static class of functions for post processing node data
*/
class nodeFunctions
{
/**
* Create a nestled array of data from a tree or branch
*
* @access public
* @param array array of data from classNodes::fetch*
* @param string Field name for 'right'
* @return Array
*/
static public function nestle( array $array, $nDepthField='level' )
{
/* Init */
$nested = array();
$depths = array();
foreach( $array as $key => $data )
{
if ( $data[ $nDepthField ] == 0 )
{
$nested[ $key ] = $data;
$depths[ $data[ $nDepthField ] + 1] = $key;
}
else
{
$parent =& $nested;
for( $i = 1; $i <= ( $data[ $nDepthField ] ); $i++ )
{
$parent =& $parent[ $depths[ $i ] ];
}
$parent['_children_'][ $key ] = $data;
$depths[ $data[ $nDepthField ] + 1 ] = $key;
}
}
return $nested;
}
}