<?php
/* Reminder: always indent with 4 spaces (no tabs). */
// +---------------------------------------------------------------------------+
// | Copyright (c) 2008, Demian Turner |
// | All rights reserved. |
// | |
// | Redistribution and use in source and binary forms, with or without |
// | modification, are permitted provided that the following conditions |
// | are met: |
// | |
// | o Redistributions of source code must retain the above copyright |
// | notice, this list of conditions and the following disclaimer. |
// | o Redistributions in binary form must reproduce the above copyright |
// | notice, this list of conditions and the following disclaimer in the |
// | documentation and/or other materials provided with the distribution. |
// | o The names of the authors may not be used to endorse or promote |
// | products derived from this software without specific prior written |
// | permission. |
// | |
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
// | |
// +---------------------------------------------------------------------------+
// | Seagull 0.6 |
// +---------------------------------------------------------------------------+
// | NestedSet.php |
// +---------------------------------------------------------------------------+
// | Author: Andy Crain <andy@newslogic.com> |
// +---------------------------------------------------------------------------+
// $Id: NestedSet.php,v 1.10 2005/04/27 23:32:41 demian Exp $
/**
* A lightweight wrapper to PEAR DB_NestedSet that bypasses NestedSet for most
* methods, querying the specified nested set table directly via PEAR DB; more
* complex, write-heavy methods are left to DB_NestedSet.
*
* @package SGL
* @author Andy Crain <andy@newslogic.com>
* @version $Revision: 1.10 $
*/
class SGL_NestedSet
{
/**
* Array of images for addImages() to use to decorate results, relative to root.
*
* @var array
* @access private
*/
var $_images = array(
'upArrow' => 'images/16/move_up.gif',
'upArrowDead' => 'images/16/move_up_dead.gif',
'downArrow' => 'images/16/move_down.gif',
'downArrowDead' => 'images/16/move_down_dead.gif',
'folder' => 'images/treeNav/foldericon.png',
'file' => 'images/treeNav/file.png',
'blank' => 'images/treeNav/blank.png',
't' => 'images/treeNav/T.png',
'l' => 'images/treeNav/L.png',
'i' => 'images/treeNav/I.png');
var $_protectedFields = array('id', 'rootid', 'l', 'r', 'norder', 'level', 'parent');
var $params = array('tableStructure' =>
array(
'id' => 'id',
'rootid' => 'rootid',
'l' => 'l',
'r' => 'r',
'norder' => 'norder',
'level' => 'level',
'parent' => 'parent'
),
'tableName' => '',
'lockTableName' => '',
'sequenceName' => '');
var $_aNodes = array();
public static function singleton($params)
{
static $aInstances;
$signature = md5(serialize($params));
if (!isset($aInstances[$signature])) {
///FIX PHP 5.3 by Witoon+Puttipong
$aInstances = new SGL_NestedSet($params);
$aInstances[$signature] = &$aInstances;
}
return $aInstances[$signature];
}
public function SGL_NestedSet($params)
{
SGL::logMessage(null, PEAR_LOG_DEBUG);
$this->dbh = $this->_getDb();
$this->_params = $params;
$this->_tableName = $params['tableName'];
$this->_fieldsInternal = array_flip($params['tableStructure']);
$this->_fieldListExternal = $this->_tableName . '.' . implode(",$this->_tableName.",$this->_fieldsInternal);
}
protected function &_getDb()
{
$locator = SGL_ServiceLocator::singleton();
$dbh = $locator->get('DB');
if (!$dbh) {
$dbh = SGL_DB::singleton();
$locator->register('DB', $dbh);
}
return $dbh;
}
public function setImage($key, $value)
{
$this->_images[$key] = $value;
}
public function setImages($imagesArray)
{
$this->_images = $imagesArray;
}
/**
* Fetches all root nodes (rootid = id) from the entire table/tree.
*
* @access public
* @param void
* @return array of node arrays
*
* @author Andy Crain <andy@newslogic.com>
* @version 1.0
* @since PHP 4.0
*/
public function getRoots($addSQL = array())
{
$cols = $this->_addSQL($addSQL, 'cols');
$join = $this->_addSQL($addSQL, 'join');
$groupBy = $this->_addSQL($addSQL, 'groupBy');
$where = $this->_addSQL($addSQL, 'where', 'AND');
// Get root nodes (id = rootid).
$sql = "SELECT $this->_fieldListExternal $cols
FROM $this->_tableName $join
WHERE {$this->_tableName}.{$this->_fieldsInternal['id']} = {$this->_tableName}.{$this->_fieldsInternal['rootid']}
$where $groupBy
ORDER BY {$this->_tableName}.{$this->_fieldsInternal['norder']}";
$result =& $this->dbh->query($sql);
if (SGL::isError($result)) {
return SGL::raiseError('SQL problem', SGL_ERROR_DBFAILURE);
}
$r = '';
///FIX PHP 5.3(use MDB2) by Witoon+Puttipong //while ($result->fetchInto($row, DB_FETCHMODE_ASSOC)){
if (SGL_DB_DRIVER == 'DB') {
while ($result->fetchInto($row, SGL_DB_FETCHMODE_ASSOC)){
$r[$row[$this->_fieldsInternal['id']]] = $row;
}
}else{
while ($row = $result->fetchRow(SGL_DB_FETCHMODE_ASSOC)){
$r[$row[$this->_fieldsInternal['id']]] = $row;
}
}
return $r;
}
/**
* Fetches all nodes from all roots, i.e., the entire table/tree.
*
* @access public
* @param void
* @return array of node arrays
*
* @author Andy Crain <andy@newslogic.com>
* @version 1.0
* @since PHP 4.0
*/
public function getTree($addSQL = array())
{
$cols = $this->_addSQL($addSQL, 'cols');
$join = $this->_addSQL($addSQL, 'join');
$groupBy = $this->_addSQL($addSQL, 'groupBy');
$where = $this->_addSQL($addSQL, 'where', 'AND');
$roots = $this->getRoots($addSQL);
// Get all descendants of each node (rootid = $rootid).
$r = '';
if (is_array($roots) && count($roots)) {
foreach($roots as $id => $root) {
$sql = "SELECT $this->_fieldListExternal $cols
FROM $this->_tableName $join
WHERE {$this->_tableName}.{$this->_fieldsInternal['rootid']} = {$root[$this->_fieldsInternal['rootid']]}
$where $groupBy
ORDER BY {$this->_tableName}.{$this->_fieldsInternal['l']}";
$result =& $this->dbh->query($sql);
if (SGL::isError($result)) {
return SGL::raiseError('SQL problem', SGL_ERROR_DBFAILURE);
}
///FIX PHP 5.3(use MDB2) by Witoon+Puttipong //while ($result->fetchInto($row, DB_FETCHMODE_ASSOC)){
if (SGL_DB_DRIVER == 'DB') {
while ($result->fetchInto($row, SGL_DB_FETCHMODE_ASSOC)){
$r[$row[$this->_fieldsInternal['id']]] = $row;
}
}else{
while ($row = $result->fetchRow(SGL_DB_FETCHMODE_ASSOC)){
$r[$row[$this->_fieldsInternal['id']]] = $row;
}
}
}
}
return $r;
}
/**
* For any node whose id is supplied, fetches branch for that node (all
* nodes with same root_id), including that node, and those above and below it.
*
* @access public
* @param int $node_id
* @return array of node arrays
*
* @author Andy Crain <andy@newslogic.com>
* @version 1.0
* @since PHP 4.0
*/
public function getBranch($node_id, $addSQL = array())
{
$cols = $this->_addSQL($addSQL, 'cols');
$join = $this->_addSQL($addSQL, 'join');
$groupBy = $this->_addSQL($addSQL, 'groupBy');
$where = $this->_addSQL($addSQL, 'where', 'AND');
// Get this node's rootnode, so we can then get nodes with matching rootid.
$node = $this->getNode($node_id);
$sql = "SELECT $this->_fieldListExternal $cols
FROM $this->_tableName $join
WHERE {$this->_tableName}.{$this->_fieldsInternal['rootid']} = {$node[$this->_fieldsInternal['rootid']]}
$where $groupBy
ORDER BY {$this->_tableName}.{$this->_fieldsInternal['l']}";
$result =& $this->dbh->query($sql);
if (SGL::isError($result)) {
return SGL::raiseError('SQL problem', SGL_ERROR_DBFAILURE);
}
///FIX PHP 5.3(use MDB2) by Witoon+Puttipong //while ($result->fetchInto($row, DB_FETCHMODE_ASSOC)){
if (SGL_DB_DRIVER == 'DB' ){
while ($result->fetchInto($row, SGL_DB_FETCHMODE_ASSOC)){
$r[$row[$this->_fieldsInternal['id']]] = $row;
}
} else {
while ($row = $result->fetchRow(SGL_DB_FETCHMODE_ASSOC)){
$r[$row[$this->_fieldsInternal['id']]] = $row;
}
}
return $r;
}
/**
* For any node, fetches all descendents (kids, grandkids, etc.)of that node (nodes with same
* rootid and with left ids bounded by this node's left and right id, and which aren't this node).
*
* @access public
* @param int $node_id
* @return array of node arrays
*
* @author Andy Crain <andy@newslogic.com>
* @version 1.0
* @since PHP 4.0
*/
public function getSubBranch($node_id, $addSQL = array())
{
$cols = $this->_addSQL($addSQL, 'cols');
$join = $this->_addSQL($addSQL, 'join');
$groupBy = $this->_addSQL($addSQL, 'groupBy');
$where = $this->_addSQL($addSQL, 'where', 'AND');
// Get this node's rootnode, left and right nodes and use to fetch children.
$node = $this->getNode($node_id);
$sql = "SELECT $this->_fieldListExternal $cols
FROM $this->_tableName $join
WHERE {$this->_tableName}.{$this->_fieldsInternal['rootid']} = {$node[$this->_fieldsInternal['rootid']]}
AND {$this->_tableName}.{$this->_fieldsInternal['l']} BETWEEN {$node[$this->_fieldsInternal['l']]} AND {$node[$this->_fieldsInternal['r']]}
AND {$this->_tableName}.{$this->_fieldsInternal['id']} <> $node_id
$where $groupBy
ORDER BY {$this->_tableName}.{$this->_fieldsInternal['l']}";
$result =& $this->dbh->query($sql);
if (SGL::isError($result)) {
return SGL::raiseError('SQL problem', SGL_ERROR_DBFAILURE);
}
$r = '';
///FIX PHP 5.3(use MDB2) by Witoon+Puttipong //while ($result->fetchInto($row, DB_FETCHMODE_ASSOC)){
if (SGL_DB_DRIVER == 'DB' ){
while ($result->fetchInto($row, SGL_DB_FETCHMODE_ASSOC)){
$r[$row[$this->_fieldsInternal['id']]] = $row;
}
} else {
while ($row = $result->fetchRow(SGL_DB_FETCHMODE_ASSOC)){
$r[$row[$this->_fieldsInternal['id']]] = $row;
}
}
return $r;
}
public function getParent($id)
{
$ns = $this->_getNestedSet();
return $ns->getParent($id);
}
/**
* For any node, fetches child nodes (nodes with same rootid, with level = parent
* level + 1, with l between parent's l and r).
*
* @access public
* @param int $node_id
* @return array of node arrays
*
* @author Andy Crain <andy@newslogic.com>
* @version 1.0
* @since PHP 4.0
*/
public function getChildren($node_id, $addSQL = array())
{
// Get this node's rootnode, left and right nodes and use to fetch children.
$node = $this->getNode($node_id);
$cols = $this->_addSQL($addSQL, 'cols');
$join = $this->_addSQL($addSQL, 'join');
$groupBy = $this->_addSQL($addSQL, 'groupBy');
$where = $this->_addSQL($addSQL, 'where', 'AND');
$sql = "SELECT $this->_fieldListExternal $cols
FROM $this->_tableName $join
WHERE {$this->_tableName}.{$this->_fieldsInternal['rootid']} = {$node[$this->_fieldsInternal['rootid']]}
AND {$this->_tableName}.{$this->_fieldsInternal['l']} BETWEEN {$node[$this->_fieldsInternal['l']]} AND {$node[$this->_fieldsInternal['r']]}
AND {$this->_tableName}.{$this->_fieldsInternal['level']} = {$node[$this->_fieldsInternal['level']]} + 1
$where $groupBy
ORDER BY {$this->_tableName}.{$this->_fieldsInternal['l']}";
$result =& $this->dbh->query($sql);
if (SGL::isError($result)) {
return SGL::raiseError('SQL problem', SGL_ERROR_DBFAILURE);
}
$r = array();
///FIX PHP 5.3(use MDB2) by Witoon+Puttipong //while ($result->fetchInto($row, DB_FETCHMODE_ASSOC)) {
if (SGL_DB_DRIVER == 'DB' ){
while ($result->fetchInto($row, SGL_DB_FETCHMODE_ASSOC)){
$r[$row[$this->_fieldsInternal['id']]] = $row;
}
} else {
while ($row = $result->fetchRow(SGL_DB_FETCHMODE_ASSOC)){
$r[$row[$this->_fieldsInternal['id']]] = $row;
}
}
return $r;
}
/**
* Borrowed from PEAR DB_NestedSet. Formats various sql clauses.
*
* @access private
* @param
* @return
*
* @author Andy Crain <andy@newslogic.com>
* @version 1.0
* @since PHP 4.0
*/
private function _addSQL($addSQL, $type, $prefix = false) {
if (!isset($addSQL[$type]) || $addSQL[$type] == '') {
return '';
}
switch ($type) {
case 'cols':
return ', ' . $addSQL[$type];
case 'where':
return $prefix . ' (' . $addSQL[$type] . ')';
default:
return $addSQL[$type];
}
}
/**
* Returns the node indentified by supplied id, or false.
*
* @access private
* @param int $node_id
* @return array | false
*
* @author Andy Crain <andy@newslogic.com>
* @version 1.0
* @since PHP 4.0
*/
public function getNode($node_id)
{
if (!isset($this->_aNodes[$node_id])) {
$sql = "SELECT $this->_fieldListExternal
FROM $this->_tableName
WHERE {$this->_fieldsInternal['id']} = $node_id";
$result =& $this->dbh->query($sql);
if (SGL::isError($result)) {
return $result;
}
///FIX PHP 5.3(use MDB2) by Witoon+Puttipong //$result->fetchInto($this->_aNodes[$node_id], DB_FETCHMODE_ASSOC);
if (SGL_DB_DRIVER == 'DB' ){
$result->fetchInto($this->_aNodes[$node_id], SGL_DB_FETCHMODE_ASSOC);
} else {
$this->_aNodes[$node_id] = $result->fetchRow(SGL_DB_FETCHMODE_ASSOC);
}
if (is_null($this->_aNodes[$node_id])) {
$this->_aNodes[$node_id] = false;
}
}
return $this->_aNodes[$node_id];
}
/**
* Returns "breadcrumbs," a node's ancestral path through the tree: same rootid,
* and a level less than this node's, and a left node less than this node's, and
* a right node greater than this node's.
*
* @access public
* @param int $node_id
* @return array of node arrays
*
* @author Andy Crain <andy@newslogic.com>
* @version 1.0
* @since PHP 4.0
*/
public function getBreadcrumbs($node_id, $addSQL = array(), $includeCurrentNode = false)
{
$cols = $this->_addSQL($addSQL, 'cols');
$join = $this->_addSQL($addSQL, 'join');
$groupBy = $this->_addSQL($addSQL, 'groupBy');
$where = $this->_addSQL($addSQL, 'where', 'AND');
$node = $this->getNode($node_id);
if ($includeCurrentNode) {
$sql = "SELECT $this->_fieldListExternal $cols
FROM $this->_tableName $join
WHERE {$this->_tableName}.{$this->_fieldsInternal['level']} <= {$node[$this->_fieldsInternal['level']]}
AND {$this->_tableName}.{$this->_fieldsInternal['l']} <= {$node[$this->_fieldsInternal['l']]}
AND {$this->_tableName}.{$this->_fieldsInternal['r']} >= {$node[$this->_fieldsInternal['r']]}
AND {$this->_tableName}.{$this->_fieldsInternal['rootid']} = {$node[$this->_fieldsInternal['rootid']]}
$where $groupBy
ORDER BY {$this->_tableName}.{$this->_fieldsInternal['l']}";
} else {
$sql = "SELECT $this->_fieldListExternal $cols
FROM $this->_tableName $join
WHERE {$this->_tableName}.{$this->_fieldsInternal['level']} < {$node[$this->_fieldsInternal['level']]}
AND {$this->_tableName}.{$this->_fieldsInternal['l']} < {$node[$this->_fieldsInternal['l']]}
AND {$this->_tableName}.{$this->_fieldsInternal['r']} > {$node[$this->_fieldsInternal['r']]}
AND {$this->_tableName}.{$this->_fieldsInternal['rootid']} = {$node[$this->_fieldsInternal['rootid']]}
$where $groupBy
ORDER BY {$this->_fieldsInternal['l']}";
}
$result =& $this->dbh->query($sql);
if (SGL::isError($result)) {
return SGL::raiseError('SQL problem', SGL_ERROR_DBFAILURE);
}
$r = array();
///FIX PHP 5.3(use MDB2) by Witoon+Puttipong //while ($result->fetchInto($row, DB_FETCHMODE_ASSOC)){
if (SGL_DB_DRIVER == 'DB') {
while ($result->fetchInto($row, SGL_DB_FETCHMODE_ASSOC)){
$r[$row[$this->_fieldsInternal['id']]] = $row;
}
}else{
while ($row = $result->fetchRow(SGL_DB_FETCHMODE_ASSOC)){
$r[$row[$this->_fieldsInternal['id']]] = $row;
}
}
return $r;
}
/**
* Takes a reference to a nodes array such as returned by getTree() et. al. and adds to
* each node array an array of images that can be used to build a MS Windows Explorer-like
* tree view, with images for file, folder, blank, and I, L, and T shapes, as well as up
* and down arrows that are grayed out when the node cannot be moved up or down (has no
* siblings above or below it).
*
* @access public
* @param array $aNodes
* @return void
*
* @author Andy Crain <andy@newslogic.com>
* @version 1.0
* @since PHP 4.0
*/
public function addImages(&$aNodes)
{
// Build sorted array $nodeMap so we can easily test whether a node has
// siblings (same parent, same level) above or below it (order-1, order+1).
if (is_array($aNodes) && count($aNodes)) {
if (!isset($nodeMap)) {
$level = $this->_fieldsInternal['level'];
$parent = $this->_fieldsInternal['parent'];
$order = $this->_fieldsInternal['norder'];
foreach($aNodes as $k => $n){
$nodeMap[$n[$level]][$n[$parent]][$n[$order]] = $k;
}
}
reset($aNodes);
while (list($id,$node) = each($aNodes)){
// If inside subtree, use I shape, else blank (for level 2 and above only,
// since rightmost 2 images are the L/T shape then folder/file).
for ($i=2; $i < $node[$this->_fieldsInternal['level']]; $i++){
if (isset($insideNest[$i]) && $insideNest[$i] == true) {
$aNodes[$id]['images']['treePad'][] = $this->_images['i'];
} else {
$aNodes[$id]['images']['treePad'][] = $this->_images['blank'];
}
}
// Only nodes with parents get T and L shapes
if ($node[$this->_fieldsInternal['l']] > 1){
// use L shape for terminal node, T shape for intermediate node
if ($node[$this->_fieldsInternal['r']] == $aNodes[$node[$this->_fieldsInternal['parent']]][$this->_fieldsInternal['r']] - 1){//terminal node
$aNodes[$id]['images']['treePad'][] = $this->_images['l'];
$insideNest[$node[$this->_fieldsInternal['level']]] = false;
} else {
$aNodes[$id]['images']['treePad'][] = $this->_images['t'];
$insideNest[$node[$this->_fieldsInternal['level']]] = true;
}
}
// Finally, add folder icon.
$aNodes[$id]['images']['treePad'][] = $this->_images['folder'];
// Using $nodeMap, assign up/down arrows and the target node id above or below
// which to move the node.
if (isset($nodeMap[$node[$this->_fieldsInternal['level']]][$node[$this->_fieldsInternal['parent']]][$node[$this->_fieldsInternal['norder']] - 1]) ) {
$aNodes[$id]['images']['moveUpImg'] = $this->_images['upArrow'];
$aNodes[$id]['images']['moveUpTarget'] = $nodeMap[$node[$this->_fieldsInternal['level']]][$node[$this->_fieldsInternal['parent']]][$node[$this->_fieldsInternal['norder']] - 1];
} else {
$aNodes[$id]['images']['moveUpImg'] = $this->_images['upArrowDead'];
$aNodes[$id]['images']['moveUpTarget'] = 0;
}
if (isset($nodeMap[$node[$this->_fieldsInternal['level']]][$node[$this->_fieldsInternal['parent']]][$node[$this->_fieldsInternal['norder']] + 1]) ) {
$aNodes[$id]['images']['moveDownImg'] = $this->_images['downArrow'];
$aNodes[$id]['images']['moveDownTarget'] = $nodeMap[$node[$this->_fieldsInternal['level']]][$node[$this->_fieldsInternal['parent']]][$node[$this->_fieldsInternal['norder']] + 1];
} else {
$aNodes[$id]['images']['moveDownImg'] = $this->_images['downArrowDead'];
$aNodes[$id]['images']['moveDownTarget'] = 0;
}
}
}
}
/**
* Updates defined fields (any field defined in params['tableStructure'] that is not
* a NestedSet field such as l, r, rootid, norder, etc. (i.e. not in _protectedFields).
*
* @access public
* @param int $id
* @param array $values (field name => field value)
* @return DB_OK | PEAR Error
*
* @author Andy Crain <andy@newslogic.com>
* @version 1.0
* @since PHP 4.0
*/
public function updateNode($id, $values)
{
$this->_cleanMemoryCache($id);
$set = implode(', ', $this->prepareValues($values, true));
$sql = "UPDATE $this->_tableName
SET $set
WHERE {$this->_fieldsInternal['id']} = $id";
$result = $this->dbh->query($sql);
$result =& $result;
if (SGL::isError($result)) {
return SGL::raiseError('SQL problem', SGL_ERROR_DBFAILURE);
}
return $result;
}
/**
* Prepares $values array for insert or update into table. Called
* with $quoteValues=true to build quoted key=value strings for update sql.
* Called externally with $quoteValues=false to simply weed out of an
* array any fields that either are not in the table or that are but are internal.
*
* @access private
* @param
* @return object DB_NestedSet_DB
*
* @author Andy Crain <andy@newslogic.com>
* @version 1.0
* @since PHP 4.0
*/
public function prepareValues($values, $quoteValues = false)
{
$r = array();
if ($quoteValues) {
foreach ($values as $k => $value) {
$internalField = array_search($k,$this->_fieldsInternal);
if ($internalField && !in_array($internalField,$this->_protectedFields)) {
$k = $this->dbh->quoteIdentifier($k);
$value = $this->dbh->quoteSmart($value);
$r[] = "$k = $value";
}
}
} else {
foreach ($values as $k => $value) {
$internalField = array_search($k,$this->_fieldsInternal);
if ($internalField && !in_array($internalField,$this->_protectedFields)) {
$r[$k] = $value;
}
}
}
return $r;
}
/**
* DB_NestedSet_DB factory. Called only by wrapper methods.
* Several methods (createRootNode() and moveTree()) when called from
* DB_NestedSet directly take constants as parameters, but since DB_NestedSet
* isn't instantiated at call time, we pass the constants' values instead.
* Values for $pos are: 'BE' (move node before target norder),
* 'AF' (move node after target norder), or 'SUB' (move node beneath, as a child
* to target). See PEAR DB_NestedSet docs for api info on wrapper methods.
*
* @access private
* @param
* @return object DB_NestedSet_DB
*
* @author Andy Crain <andy@newslogic.com>
*/
private function _getNestedSet()
{
static $ns;
if (is_null($ns)) {
require_once 'DB/NestedSet.php';
// create an instance of DB_NestedSet_DB
$ns = & DB_NestedSet::factory(SGL_DB_DRIVER, SGL_DB::getDsn(), $this->_params['tableStructure']);
///Test
if (SGL_DB_DRIVER == 'MDB2') {
$ns->db->setOption('seqcol_name', 'id');
}
if (is_a($ns, 'PEAR_Error')) {
echo $ns->getCode() . ': ' . $ns->getMessage();
}
$ns->setAttr(array(
'node_table' => $this->_tableName,
'lock_table' => $this->_params['lockTableName'],
'sequence_table' => $this->_params['sequenceName'])
);
}
return $ns;
}
/**
* The following are all just wrappers to DB_NestedSet, an instance of which is
* returned by _getNestedSet(). See PEAR/DB/NestedSet.php for API docs.
*/
public function createRootNode($values, $id = false, $first = false, $pos = 'AF')
{
$ns = $this->_getNestedSet();
return $ns->createRootNode($values, $id, $first, $pos);
}
public function createSubNode($id, $values)
{
$this->_cleanMemoryCache($id);
$ns = $this->_getNestedSet();
return $ns->createSubNode($id, $values);
}
public function createLeftNode($id, $values)
{
$this->_cleanMemoryCache($id);
$ns = $this->_getNestedSet();
return $ns->createLeftNode($id, $values);
}
public function createRightNode($id, $values)
{
$this->_cleanMemoryCache($id);
$ns = $this->_getNestedSet();
return $ns->createRightNode($id, $values);
}
public function moveTree($id, $targetid, $pos, $copy = false)
{
$this->_cleanMemoryCache();
$ns = $this->_getNestedSet();
return $ns->moveTree($id, $targetid, $pos, $copy);
}
public function deleteNode($id)
{
$this->_cleanMemoryCache($id);
$ns = $this->_getNestedSet();
return $ns->deleteNode($id);
}
/**
* Clean nodes stored in memory
* @param integer node id [optional]
* @access private
*/
private function _cleanMemoryCache($id = null)
{
if (is_null($id)) {
//clear all nodes
$this->_aNodes = array();
} elseif (array_key_exists($id, $this->_aNodes)) {
//clear the given node
unset($this->_aNodes[$id]);
}
}
}
?>
Copyright 2K16 - 2K18 Indonesian Hacker Rulez