Skip to content

Instantly share code, notes, and snippets.

@CloCkWeRX
Created January 4, 2012 22:23
Show Gist options
  • Save CloCkWeRX/1562520 to your computer and use it in GitHub Desktop.
Save CloCkWeRX/1562520 to your computer and use it in GitHub Desktop.
Tree - 0_3_0 vs trunk
Index: Tree/Error.php
===================================================================
--- Tree/Error.php (.../branches/Tree_0_3_0) (revision 321102)
+++ Tree/Error.php (.../trunk) (revision 321102)
@@ -1,86 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4: */
-// +----------------------------------------------------------------------+
-// | PHP Version 4 |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2003 The PHP Group |
-// +----------------------------------------------------------------------+
-// | This source file is subject to version 2.02 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: Wolfram Kriesing <wolfram@kriesing.de> |
-// +----------------------------------------------------------------------+
-//
-// $Id$
-require_once 'PEAR.php';
-
-/**
- * Errors constants definitions
- */
-define('TREE_ERROR_NOT_IMPLEMENTED', -1);
-define('TREE_ERROR_ELEMENT_NOT_FOUND', -2);
-define('TREE_ERROR_INVALID_NODE_NAME', -3);
-define('TREE_ERROR_MOVE_TO_CHILDREN', -4);
-define('TREE_ERROR_PARENT_ID_MISSED', -5);
-define('TREE_ERROR_INVALID_PARENT', -6);
-define('TREE_ERROR_EMPTY_PATH', -7);
-define('TREE_ERROR_INVALID_PATH', -8);
-define('TREE_ERROR_DB_ERROR', -9);
-define('TREE_ERROR_PATH_SEPARATOR_EMPTY',-10);
-define('TREE_ERROR_CANNOT_CREATE_FOLDER',-11);
-define('TREE_ERROR_UNKNOW_ERROR', -99);
-
-/**
- *
- *
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @package Tree
- */
-class Tree_Error extends PEAR_Error
-{
- /**
- * @var string prefix for error messages.
- */
- var $error_message_prefix = "Tree Error: ";
-
- // {{{ Tree_Error()
-
- /**
- * @access public
- * @version 2002/03/03
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- */
- function Tree_Error($msg, $line, $file,
- $mode = null, $userinfo = 'no userinfo')
- {
- $this->PEAR_Error(sprintf("%s <br/>in %s [%d].", $msg, $file, $line),
- null , $mode , null, $userinfo );
- }
-
- // }}}
- // {{{ getMessage()
-
- function getMessage($id)
- {
- $messages = array(
- TREE_ERROR_NOT_IMPLEMENTED => '',
- TREE_ERROR_INVALID_PATH => '',
- TREE_ERROR_DB_ERROR => '',
- TREE_ERROR_PARENT_ID_MISSED => '',
- TREE_ERROR_MOVE_TO_CHILDREN => '',
- TREE_ERROR_ELEMENT_NOT_FOUND => '',
- TREE_ERROR_PATH_SEPARATOR_EMPTY => '',
- TREE_ERROR_INVALID_NODE_NAME => '',
- TREE_ERROR_UNKNOW_ERROR => ''
- );
- return isset($messages[$id])?$messages[$id]:
- $messages[TREE_ERROR_UNKNOW_ERROR];
- }
-
- // }}}
-}
\ No newline at end of file
Index: Tree/OptionsMDB.php
===================================================================
--- Tree/OptionsMDB.php (.../branches/Tree_0_3_0) (revision 321102)
+++ Tree/OptionsMDB.php (.../trunk) (revision 321102)
@@ -1,113 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4: */
-// i think this class should go somewhere in a common PEAR-place,
-// because a lot of classes use options, at least PEAR::DB does
-// but since it is not very fancy to crowd the PEAR-namespace
-// too much i dont know where to put it yet :-(
-
-// +----------------------------------------------------------------------+
-// | PHP Version 4 |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2003 The PHP Group |
-// +----------------------------------------------------------------------+
-// | This source file is subject to version 2.02 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: Wolfram Kriesing <wolfram@kriesing.de> |
-// +----------------------------------------------------------------------+
-//
-// $Id$
-
-require_once 'Tree/Common.php';
-
-/**
-* this class additionally retreives a DB connection and saves it
-* in the property "dbh"
-*
-* @package Tree
-* @access public
-* @author Wolfram Kriesing <wolfram@kriesing.de>
-*
-*/
-class Tree_OptionsMDB extends Tree_Common
-{
- /**
- * @var object
- */
- var $dbh;
-
- // {{{ Tree_OptionsMDB()
-
- /**
- * this constructor sets the options, since i normally need this and
- * in case the constructor doesnt need to do anymore i already have
- * it done :-)
- *
- * @version 02/01/08
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param boolean true if loggedIn
- */
- function Tree_OptionsMDB($dsn, $options=array())
- {
- $res = $this->_connectDB($dsn);
- if (PEAR::isError($res)) {
- return $res;
- }
-
- $this->dbh->setFetchmode(MDB_FETCHMODE_ASSOC);
- // do options afterwards since it overrules
- $this->Tree_Options($options);
- }
-
- // }}}
- // {{{ _connectDB()
-
- /**
- * Connect to database by using the given DSN string
- *
- * @author copied from PEAR::Auth, Martin Jansen, slightly modified
- * @access private
- * @param string DSN string
- * @return mixed Object on error, otherwise bool
- */
- function _connectDB($dsn)
- {
- // only include the db if one really wants to connect
- require_once 'MDB.php';
-
- if (is_string($dsn) || is_array($dsn)) {
- $this->dbh = MDB::Connect($dsn);
- } else {
- if (strtolower(get_parent_class($dsn)) == 'mdb_common') {
- $this->dbh = $dsn;
- } else {
- if (is_object($dsn) && MDB::isError($dsn)) {
- return new MDB_Error($dsn->code, PEAR_ERROR_DIE);
- }
-
- return new PEAR_Error(
- 'The given dsn was not valid in file '.
- __FILE__ . ' at line ' . __LINE__,
- 41,
- PEAR_ERROR_RETURN,
- null,
- null
- );
- }
- }
-
- if (MDB::isError($this->dbh)) {
- return new MDB_Error($this->dbh->code, PEAR_ERROR_DIE);
- }
-
- return true;
- }
-
- // }}}
-}
\ No newline at end of file
Index: Tree/OptionsMDB2.php
===================================================================
--- Tree/OptionsMDB2.php (.../branches/Tree_0_3_0) (revision 321102)
+++ Tree/OptionsMDB2.php (.../trunk) (revision 321102)
@@ -1,114 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4: */
-// i think this class should go somewhere in a common PEAR-place,
-// because a lot of classes use options, at least PEAR::DB does
-// but since it is not very fancy to crowd the PEAR-namespace
-// too much i dont know where to put it yet :-(
-
-// +----------------------------------------------------------------------+
-// | PHP Version 4 |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2003 The PHP Group |
-// +----------------------------------------------------------------------+
-// | This source file is subject to version 2.02 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: Wolfram Kriesing <wolfram@kriesing.de> |
-// +----------------------------------------------------------------------+
-//
-// $Id$
-
-require_once 'Tree/Common.php';
-
-/**
-* this class additionally retreives a DB connection and saves it
-* in the property "dbh"
-*
-* @package Tree
-* @access public
-* @author Wolfram Kriesing <wolfram@kriesing.de>
-*
-*/
-class Tree_OptionsMDB2 extends Tree_Common
-{
- /**
- * @var object
- */
- var $dbh;
-
- // {{{ Tree_OptionsMDB2()
-
- /**
- * this constructor sets the options, since i normally need this and
- * in case the constructor doesnt need to do anymore i already have
- * it done :-)
- *
- * @version 02/01/08
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param boolean true if loggedIn
- */
- function Tree_OptionsMDB2($dsn, $options = array())
- {
- $res = $this->_connectDB($dsn);
- if (PEAR::isError($res)) {
- return $res;
- }
-
- $this->dbh->setFetchmode(MDB2_FETCHMODE_ASSOC);
- // do options afterwards since it overrules
- $this->Tree_Options($options);
- }
-
- // }}}
- // {{{ _connectDB()
-
- /**
- * Connect to database by using the given DSN string
- *
- * @author copied from PEAR::Auth, Martin Jansen, slightly modified
- * @access private
- * @param string DSN string
- * @return mixed Object on error, otherwise bool
- */
- function _connectDB($dsn)
- {
- // only include the db if one really wants to connect
- require_once 'MDB2.php';
-
- if (is_string($dsn) || is_array($dsn)) {
- $this->dbh = MDB2::Connect($dsn);
- } else {
- if (MDB2::isConnection($dsn)) {
- $this->dbh = $dsn;
- } else {
- if (is_object($dsn) && MDB2::isError($dsn)) {
- return new MDB2_Error($dsn->code, PEAR_ERROR_DIE);
- }
-
- return new PEAR_Error(
- 'The given dsn was not valid in file '.
- __FILE__ . ' at line ' . __LINE__,
- 41,
- PEAR_ERROR_RETURN,
- null,
- null
- );
-
- }
- }
-
- if (MDB2::isError($this->dbh)) {
- return new MDB2_Error($this->dbh->code, PEAR_ERROR_DIE);
- }
-
- return true;
- }
-
- // }}}
-}
\ No newline at end of file
Index: Tree/OptionsDB.php
===================================================================
--- Tree/OptionsDB.php (.../branches/Tree_0_3_0) (revision 321102)
+++ Tree/OptionsDB.php (.../trunk) (revision 321102)
@@ -1,122 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4: */
-
-// i think this class should go somewhere in a common PEAR-place,
-// but since it is not very fancy to crowd the PEAR-namespace too much
-// i dont know where to put it yet :-(
-
-//
-// +----------------------------------------------------------------------+
-// | PHP Version 4 |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2003 The PHP Group |
-// +----------------------------------------------------------------------+
-// | This source file is subject to version 2.02 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: Wolfram Kriesing <wolfram@kriesing.de> |
-// +----------------------------------------------------------------------+
-//
-// $Id$
-
-require_once 'Tree/Common.php';
-
-/**
- * this class additionally retreives a DB connection and saves it
- * in the property "dbh"
- *
- * @package Tree
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- *
- */
-class Tree_OptionsDB extends Tree_Common
-{
- /**
- * @var object
- */
- var $dbh;
-
-
- // {{{ Tree_OptionsDB()
-
- /**
- * this constructor sets the options, since i normally need this and
- * in case the constructor doesnt need to do anymore i already have
- * it done :-)
- *
- * @version 02/01/08
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param boolean true if loggedIn
- */
- function Tree_OptionsDB($dsn , $options = array())
- {
- $res = $this->_connectDB($dsn);
- if (PEAR::isError($res)) {
- return $res;
- }
-
- $this->dbh->setFetchmode(DB_FETCHMODE_ASSOC);
- // do options afterwards since it overrules
- $this->Tree_Options($options);
- }
-
- // }}}
- // {{{ _connectDB()
-
- /**
- * Connect to database by using the given DSN string
- *
- * @author copied from PEAR::Auth, Martin Jansen, slightly modified
- * @access private
- * @param string DSN string
- * @return mixed Object on error, otherwise bool
- */
- function _connectDB($dsn)
- {
- // only include the db if one really wants to connect
- require_once 'DB.php';
-
- if (is_string($dsn) || is_array($dsn)) {
- // put the dsn parameters in an array
- // DB would be confused with an additional URL-queries,
- //like ?table=... so we do it before connecting to the DB
- if (is_string($dsn)) {
- $dsn = DB::parseDSN($dsn);
- }
- $this->dbh = DB::Connect($dsn);
- } else {
- if (strtolower(get_parent_class($dsn)) == 'db_common') {
- $this->dbh = $dsn;
- } else {
- if (is_object($dsn) && DB::isError($dsn)) {
- return new DB_Error($dsn->code, PEAR_ERROR_DIE);
- }
-
- return new PEAR_Error(
- 'The given dsn was not valid in file '.
- __FILE__ . " at line " . __LINE__,
- 41,
- PEAR_ERROR_RETURN,
- null,
- null
- );
-
- }
- }
-
- if (DB::isError($this->dbh)) {
- return new DB_Error($this->dbh->code, PEAR_ERROR_DIE);
- }
-
- return true;
- }
-
- // }}}
-}
\ No newline at end of file
Index: Tree/Common.php
===================================================================
--- Tree/Common.php (.../branches/Tree_0_3_0) (revision 321102)
+++ Tree/Common.php (.../trunk) (revision 321102)
@@ -1,845 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4: */
-// +----------------------------------------------------------------------+
-// | PHP Version 4 |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2003 The PHP Group |
-// +----------------------------------------------------------------------+
-// | This source file is subject to version 2.02 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: Wolfram Kriesing <wolfram@kriesing.de> |
-// +----------------------------------------------------------------------+
-//
-// $Id$
-
-require_once 'Tree/Tree.php';
-require_once 'Tree/Error.php';
-
-/**
- * common tree class, implements common functionality
- *
- *
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @version 2001/06/27
- * @package Tree
- */
-class Tree_Common
-{
- /**
- * @var array you need to overwrite this array and give the keys/
- * that are allowed
- */
- var $_forceSetOption = false;
-
- /**
- * put proper value-keys are given in each class, depending
- * on the implementation only some options are needed or allowed,
- * see the classes which extend this one
- *
- * @access public
- * @var array saves the options passed to the constructor
- */
- var $options = array();
-
-
- // {{{ getChildId()
-
- /**
- * @version 2002/01/18
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- */
- function getChildId($id)
- {
- $child = $this->getChild($id);
- return $child['id'];
- }
-
- // }}}
- // {{{ getChildrenIds()
-
- /**
- * get the ids of the children of the given element
- *
- * @version 2002/02/06
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param integer ID of the element that the children shall be
- * retreived for
- * @param integer how many levels deep into the tree
- * @return mixed an array of all the ids of the children of the element
- * with id=$id, or false if there are no children
- */
- function getChildrenIds($id, $levels = 1)
- {
- // returns false if no children exist
- if (!($children = $this->getChildren($id, $levels))) {
- return array();
- }
- // return an empty array, if you want to know
- // if there are children, use hasChildren
- if ($children && sizeof($children)) {
- foreach ($children as $aChild) {
- $childrenIds[] = $aChild['id'];
- }
- }
-
- return $childrenIds;
- }
-
- // }}}
- // {{{ getAllChildren()
-
- /**
- * gets all the children and grand children etc.
- *
- * @version 2002/09/30
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param integer ID of the element that the children shall be
- * retreived for
- *
- * @return mixed an array of all the children of the element with
- * id=$id, or false if there are no children
- */
- // FIXXXME remove this method and replace it by getChildren($id,0)
- function getAllChildren($id)
- {
- $retChildren = false;
- if ($children = $this->hasChildren($id)) {
- $retChildren = $this->_getAllChildren($id);
- }
- return $retChildren;
- }
-
- // }}}
- // {{{ _getAllChildren()
-
- /**
- * this method gets all the children recursively
- *
- * @see getAllChildren()
- * @version 2002/09/30
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param integer ID of the element that the children shall be
- * retreived for
- *
- * @return mixed an array of all the ids of the children of the element
- * with id=$id, or false if there are no children
- */
- function &_getAllChildren($id)
- {
- $retChildren = array();
- if ($children = $this->getChildren($id)) {
- foreach ($children as $key => $aChild) {
- $retChildren[] = &$children[$key];
- $retChildren = array_merge($retChildren,
- $this->_getAllChildren($aChild['id']));
- }
- }
- return $retChildren;
- }
-
- // }}}
- // {{{ getAllChildrenIds()
-
- /**
- * gets all the children-ids and grand children-ids
- *
- * @version 2002/09/30
- * @access public
- * @author Kriesing <wolfram@kriesing.de>
- * @param integer ID of the element that the children shall
- * be retreived for
- *
- * @return mixed an array of all the ids of the children of the element
- * with id=$id,
- * or false if there are no children
- */
- function getAllChildrenIds($id)
- {
- $childrenIds = array();
- if ($allChildren = $this->getAllChildren($id)) {
- $childrenIds = array();
- foreach ($allChildren as $aNode) {
- $childrenIds[] = $aNode['id'];
- }
- }
- return $childrenIds;
- }
-
- // }}}
- // {{{ getParentId()
-
- /**
- * get the id of the parent for the given element
- *
- * @version 2002/01/18
- * @access public
- * @param integer the id of the element for which the parentId
- * shall be retreived
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- */
- function getParentId($id)
- {
- $parent = $this->getParent($id);
- return $parent['id'];
- }
-
- // }}}
- // {{{ getParents()
-
- /**
- * this gets all the preceeding nodes, the parent and it's parent and so on
- *
- * @version 2002/08/19
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param integer the id of the element for which the parentId shall
- * be retreived
- * @return array of the parent nodes including the node with id $id
- */
- function getParents($id)
- {
- $path = $this->getPath($id);
- $parents = array();
- if (sizeof($path)) {
- foreach($path as $aNode) {
- $parents[] = $aNode;
- }
- }
- return $parents;
- }
-
- // }}}
- // {{{ getParentsIds()
-
- /**
- * get the ids of the parents and all it's parents and so on
- * it simply returns the ids of the elements returned by getParents()
- *
- * @see getParents()
- * @version 2002/08/19
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param integer $id the id of the element for which the parentId
- * shall be retreived
- *
- * @return array of the ids
- */
- function getParentsIds($id)
- {
- $parents = $this->getParents($id);
- $parentsIds = array();
- if (sizeof($parents)) {
- foreach($parents as $aNode) {
- $parentsIds[] = $aNode['id'];
- }
- }
- return $parentsIds;
- }
-
- // }}}
- // {{{ getNextId()
-
- /**
- * @version 2002/01/18
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- */
- function getNextId($id)
- {
- $next = $this->getNext($id);
- return $next['id'];
- }
-
- // }}}
- // {{{ getPreviousId()
-
- /**
- * @version 2002/01/18
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- */
- function getPreviousId($id)
- {
- $previous = $this->getPrevious($id);
- return $previous['id'];
- }
-
- // }}}
- // {{{ getLeftId()
-
- /**
- * @version 2002/01/18
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- */
- function getLeftId($id)
- {
- $left = $this->getLeft($id);
- return $left['id'];
- }
-
- // }}}
- // {{{ getRightId()
-
- /**
- * @version 2002/01/18
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- */
- function getRightId($id)
- {
- $right = $this->getRight($id);
- return $right['id'];
- }
-
- // }}}
- // {{{ getFirstRootId()
-
- /**
- * @version 2002/04/16
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- */
- function getFirstRootId()
- {
- $firstRoot = $this->getFirstRoot();
- return $firstRoot['id'];
- }
-
- // }}}
- // {{{ getRootId()
-
- /**
- * @version 2002/04/16
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- */
- function getRootId()
- {
- $firstRoot = $this->getRoot();
- return $firstRoot['id'];
- }
-
- // }}}
- // {{{ getPathAsString()
-
- /**
- * returns the path as a string
- *
- * @access public
- * @version 2002/03/28
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param mixed $id the id of the node to get the path for
- * @param integer If offset is positive, the sequence will
- * start at that offset in the array . If
- * offset is negative, the sequence will start that far
- * from the end of the array.
- * @param integer If length is given and is positive, then
- * the sequence will have that many elements in it. If
- * length is given and is negative then the
- * sequence will stop that many elements from the end of
- * the array. If it is omitted, then the sequence will
- * have everything from offset up until the end
- * of the array.
- * @param string you can tell the key the path shall be used to be
- * constructed with i.e. giving 'name' (=default) would
- * use the value of the $element['name'] for the node-name
- * (thanks to Michael Johnson).
- *
- * @return array this array contains all elements from the root
- * to the element given by the id
- */
- function getPathAsString($id, $seperator = '/',
- $offset = 0, $length = 0, $key = 'name')
- {
- $path = $this->getPath($id);
- foreach ($path as $aNode) {
- $pathArray[] = $aNode[$key];
- }
-
- if ($offset) {
- if ($length) {
- $pathArray = array_slice($pathArray, $offset, $length);
- } else {
- $pathArray = array_slice($pathArray, $offset);
- }
- }
-
- $pathString = '';
- if (sizeof($pathArray)) {
- $pathString = implode($seperator, $pathArray);
- }
- return $pathString;
- }
-
- // }}}
-
-
- //
- // abstract methods, those should be overwritten by the implementing class
- //
-
- // {{{ getPath()
-
- /**
- * gets the path to the element given by its id
- *
- * @abstract
- * @version 2001/10/10
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param mixed $id the id of the node to get the path for
- * @return array this array contains all elements from the root
- * to the element given by the id
- */
- function getPath($id)
- {
- return $this->_raiseError(TREE_ERROR_NOT_IMPLEMENTED,
- __FUNCTION__, __LINE__);
- }
-
- // }}}
- // {{{ _preparePath()
-
- /**
- * gets the path to the element given by its id
- *
- * @version 2003/05/11
- * @access private
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param mixed $id the id of the node to get the path for
- * @return array this array contains the path elements and the sublevels
- * to substract if no $cwd has been given.
- */
- function _preparePath($path, $cwd = '/', $separator = '/'){
- $elems = explode($separator, $path);
- $cntElems = sizeof($elems);
- // beginning with a slash
- if (empty($elems[0])) {
- $beginSlash = true;
- array_shift($elems);
- $cntElems--;
- }
- // ending with a slash
- if (empty($elems[$cntElems-1])) {
- $endSlash = true;
- array_pop($elems);
- $cntElems--;
- }
- // Get the real path, and the levels
- // to substract if required
- $down = 0;
- while ($elems[0] == '..') {
- array_shift($elems);
- $down++;
- }
- if ($down >= 0 && $cwd == '/') {
- $down = 0;
- $_elems = array();
- $sublevel = 0;
- $_elems = array();
- } else {
- list($_elems, $sublevel) = $this->_preparePath($cwd);
- }
- $i = 0;
- foreach($elems as $val){
- if (trim($val) == '') {
- return $this->_raiseError(TREE_ERROR_INVALID_PATH,
- __FUNCTION__, __LINE__);
- }
- if ($val == '..') {
- if ($i == 0) {
- $down++;
- } else {
- $i--;
- }
- } else {
- $_elems[$i++] = $val;
- }
- }
- if (sizeof($_elems) < 1){
- return $this->_raiseError(TREE_ERROR_EMPTY_PATH,
- __FUNCTION__, __LINE__);
- }
- return array($_elems, $sublevel);
- }
-
- // }}}
- // {{{ getLevel()
-
- /**
- * get the level, which is how far below the root the element
- * with the given id is
- *
- * @abstract
- * @version 2001/11/25
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param mixed $id the id of the node to get the level for
- *
- */
- function getLevel($id)
- {
- return $this->_raiseError(TREE_ERROR_NOT_IMPLEMENTED,
- __FUNCTION__, __LINE__);
- }
-
- // }}}
- // {{{ isChildOf()
-
- /**
- * returns if $childId is a child of $id
- *
- * @abstract
- * @version 2002/04/29
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param int id of the element
- * @param int id of the element to check if it is a child
- * @param boolean if this is true the entire tree below is checked
- * @return boolean true if it is a child
- */
- function isChildOf($id, $childId, $checkAll = true)
- {
- return $this->_raiseError(TREE_ERROR_NOT_IMPLEMENTED,
- __FUNCTION__, __LINE__);
- }
-
- // }}}
- // {{{ getIdByPath()
-
- /**
- *
- *
- */
- function getIdByPath($path, $startId = 0,
- $nodeName = 'name', $seperator = '/')
- {
- return $this->_raiseError(TREE_ERROR_NOT_IMPLEMENTED,
- __FUNCTION__, __LINE__);
- }
-
- // }}}
- // {{{ getDepth()
-
- /**
- * return the maximum depth of the tree
- *
- * @version 2003/02/25
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @return int the depth of the tree
- */
- function getDepth()
- {
- return $this->_treeDepth;
- }
-
- // }}}
-
- //
- // PRIVATE METHODS
- //
-
- // {{{ _prepareResults()
-
- /**
- * prepare multiple results
- *
- * @see _prepareResult()
- * @access private
- * @version 2002/03/03
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param array the data to prepare
- * @return array prepared results
- */
- function &_prepareResults($results)
- {
- $newResults = array();
- foreach ($results as $key => $aResult) {
- $newResults[$key] = $this->_prepareResult($aResult);
- }
- return $newResults;
- }
-
- // }}}
- // {{{ _prepareResult()
-
- /**
- * map back the index names to get what is expected
- *
- * @access private
- * @version 2002/03/03
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param array a result
- * @return array the prepared result
- */
- function _prepareResult($result)
- {
- $map = $this->getOption('columnNameMaps');
- if ($map) {
- foreach ($map as $key => $columnName) {
- if (isset($result[$columnName])) {
- $temp = $result[$columnName]; // remember the value from the old name
- unset($result[$columnName]); // remove the old one
- $result[$key] = $temp; // save it in the mapped col-name
- }
- }
- }
- return $result;
- }
-
- // }}}
- // {{{ _getColName()
-
- /**
- * this method retrieves the real column name, as used in the DB
- * since the internal names are fixed, to be portable between different
- * DB-column namings, we map the internal name to the real column name here
- *
- * @access private
- * @version 2002/03/02
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param string the internal name used
- * @return string the real name of the column
- */
- function _getColName($internalName)
- {
- if ($map = $this->getOption('columnNameMaps')) {
- if (isset($map[$internalName])) {
- return $map[$internalName];
- }
- }
- return $internalName;
- }
-
- // }}}
- // {{{ _raiseError()
-
- /**
- *
- *
- * @access private
- * @version 2002/03/02
- * @author Pierre-Alain Joye <paj@pearfr.org>
- * @param string the error message
- * @param int the line in which the error occured
- * @param mixed the error mode
- * @return object a Tree_Error
- */
- function _raiseError($errorCode, $msg = '', $line = 0)
- {
- include_once 'Tree/Error.php';
- return new Tree_Error(
- $msg, $line, __FILE__, $mode, $this->dbh->last_query);
- }
-
- // }}}
- // {{{ _throwError()
-
- /**
- *
- *
- * @access private
- * @version 2002/03/02
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param string the error message
- * @param int the line in which the error occured
- * @param mixed the error mode
- * @return object a Tree_Error
- */
- function _throwError($msg, $line, $mode = null)
- {
- include_once 'Tree/Error.php';
- if ($mode === null && $this->debug > 0) {
- $mode = PEAR_ERROR_PRINT;
- }
- return new Tree_Error(
- $msg, $line, __FILE__, $mode, $this->dbh->last_query);
- }
-
- // }}}
-
-
- /*******************************************************************************/
- /************************ METHODS FROM Tree_Memory *****************************/
- /*******************************************************************************/
-
- /**
- * returns if the given element has any children
- *
- * @version 2001/12/17
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param integer $id the id of the node to check for children
- * @return boolean true if the node has children
- */
- function hasChildren($id = 0)
- {
- if (isset($this->data[$id]['children']) &&
- sizeof($this->data[$id]['children']) > 0) {
- return true;
- }
- return false;
- }
-
-
-
-
-
- /*******************************************************************************/
- /************************ METHODS FROM Tree_Options ****************************/
- /*******************************************************************************/
-
-
-
- // {{{ Tree_Options()
-
- /**
- * this constructor sets the options, since i normally need this and
- * in case the constructor doesnt need to do anymore i already have
- * it done :-)
- *
- * @version 02/01/08
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param array the key-value pairs of the options that shall be set
- * @param boolean if set to true options are also set
- * even if no key(s) was/were found in the options property
- */
- function Tree_Options($options=array(), $force=false)
- {
- $this->_forceSetOption = $force;
- if (is_array($options) && sizeof($options)) {
- foreach ($options as $key=>$value) {
- $this->setOption($key, $value);
- }
- }
- }
-
- // }}}
- // {{{ setOption()
-
- /**
- *
- * @access public
- * @author Stig S. Baaken
- * @param string the option name
- * @param mixed the value for this option
- * @param boolean if set to true options are also set
- * even if no key(s) was/were found in the options property
- */
- function setOption($option, $value, $force = false)
- {
- // if the value is an array extract the keys
- // and apply only each value that is set
- if (is_array($value)) {
- // so we dont override existing options inside an array
- // if an option is an array
- foreach ($value as $key=>$aValue) {
- $this->setOption(array($option,$key),$aValue);
- }
- return true;
- }
-
- if (is_array($option)) {
- $mainOption = $option[0];
- $options = "['".implode("']['",$option)."']";
- $evalCode = "\$this->options".$options." = \$value;";
- } else {
- $evalCode = "\$this->options[\$option] = \$value;";
- $mainOption = $option;
- }
-
- if ($this->_forceSetOption == true ||
- $force == true || isset($this->options[$mainOption])) {
- eval($evalCode);
- return true;
- }
- return false;
- }
-
- // }}}
- // {{{ setOptions()
-
- /**
- * set a number of options which are simply given in an array
- *
- * @access public
- * @param array the values to set
- * @param boolean if set to true options are also set even if no key(s)
- * was/were found in the options property
- */
- function setOptions($options, $force = false)
- {
- if (is_array($options) && sizeof($options)) {
- foreach ($options as $key => $value) {
- $this->setOption($key, $value, $force);
- }
- }
- }
-
- // }}}
- // {{{ getOption()
-
- /**
- *
- * @access public
- * @author copied from PEAR: DB/commmon.php
- * @param boolean true on success
- */
- function getOption($option)
- {
- if (func_num_args() > 1 &&
- is_array($this->options[$option])) {
- $args = func_get_args();
- $evalCode = "\$ret = \$this->options['".
- implode("']['", $args) . "'];";
- eval($evalCode);
- return $ret;
- }
-
- if (isset($this->options[$option])) {
- return $this->options[$option];
- }
- return false;
- }
-
- // }}}
- // {{{ getOptions()
-
- /**
- * returns all the options
- *
- * @version 02/05/20
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @return string all options as an array
- */
- function getOptions()
- {
- return $this->options;
- }
-
- // }}}
-}
-
-/*
- * Local Variables:
- * mode: php
- * tab-width: 4
- * c-basic-offset: 4
- * End:
- */
\ No newline at end of file
Index: Tree/Dynamic/MDBnested.php
===================================================================
--- Tree/Dynamic/MDBnested.php (.../branches/Tree_0_3_0) (revision 321102)
+++ Tree/Dynamic/MDBnested.php (.../trunk) (revision 321102)
@@ -1,1283 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4: */
-// +----------------------------------------------------------------------+
-// | PHP Version 4 |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2003 The PHP Group |
-// +----------------------------------------------------------------------+
-// | This source file is subject to version 2.02 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: |
-// +----------------------------------------------------------------------+
-//
-// $Id$
-
-require_once 'Tree/OptionsMDB.php';
-
-/**
-* This class implements methods to work on a tree saved using the nested
-* tree model.
-* explaination: http://research.calacademy.org/taf/proceedings/ballew/index.htm
-*
-* @access public
-* @package Tree
-*/
-class Tree_Dynamic_MDBnested extends Tree_OptionsMDB
-{
-
- // {{{ properties
- var $debug = 0;
-
- var $options = array(
- // FIXXME to be implemented
- // add on for the where clause, this string is simply added
- // behind the WHERE in the select so you better make sure
- // its correct SQL :-), i.e. 'uid=3'
- // this is needed i.e. when you are saving many trees in one db-table
- 'whereAddOn'=>'',
- 'table' =>'',
- // since the internal names are fixed, to be portable between different
- // DB tables with different column namings, we map the internal name
- // to the real column name using this array here, if it stays empty
- // the internal names are used, which are:
- // id, left, right
- 'columnNameMaps'=>array(
- // since mysql at least doesnt support 'left' ...
- 'left' => 'l',
- // ...as a column name we set default to the first
- //letter only
- 'right' => 'r',
- // parent id
- 'parentId' => 'parent'
- ),
- // needed for sorting the tree, currently only used in Memory_DBnested
- 'order' => ''
- );
-
- // }}}
- // {{{ __construct()
-
- // the defined methods here are proposals for the implementation,
- // they are named the same, as the methods in the "Memory" branch.
- // If possible it would be cool to keep the same naming. And
- // if the same parameters would be possible too then it would be
- // even better, so one could easily change from any kind
- // of tree-implementation to another, without changing the source
- // code, only the setupXXX would need to be changed
- /**
- *
- *
- * @access public
- * @version 2002/03/02
- * @param string the DSN for the DB connection
- * @return void
- */
- function __construct($dsn, $options = array())
- {
- $this->Tree_Dynamic_MDBnested($dsn, $options);
- }
-
- // }}}
- // {{{ Tree_Dynamic_DBnested()
-
- /**
- *
- *
- * @access public
- * @version 2002/03/02
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param string the DSN for the DB connection
- * @return void
- */
- function Tree_Dynamic_MDBnested($dsn, $options = array())
- {
- parent::Tree_OptionsMDB($dsn, $options); // instanciate DB
- $this->table = $this->getOption('table');
- }
-
- // }}}
- // {{{ add()
-
- /**
- * add a new element to the tree
- * there are three ways to use this method
- * Method 1:
- * Give only the $parentId and the $newValues will be inserted
- * as the first child of this parent
- * <code>
- * // insert a new element under the parent with the ID=7
- * $tree->add(array('name'=>'new element name'), 7);
- * </code>
- *
- * Method 2:
- * Give the $prevId ($parentId will be dismissed) and the new element
- * will be inserted in the tree after the element with the ID=$prevId
- * the parentId is not necessary because the prevId defines exactly where
- * the new element has to be place in the tree, and the parent is
- * the same as for the element with the ID=$prevId
- * <code>
- * // insert a new element after the element with the ID=5
- * $tree->add(array('name'=>'new'), 0, 5);
- * </code>
- *
- * Method 3:
- * neither $parentId nor prevId is given, then the root element will be
- * inserted. This requires that programmer is responsible to confirm this.
- * This method does not yet check if there is already a root element saved!
- *
- * @access public
- * @param array $newValues this array contains the values that shall
- * be inserted in the db-table
- * @param integer $parentId the id of the element which shall be
- * the parent of the new element
- * @param integer $prevId the id of the element which shall preceed
- * the one to be inserted use either
- * 'parentId' or 'prevId'.
- * @return integer the ID of the element that had been inserted
- */
- function add($newValues, $parentId = 0, $prevId = 0)
- {
- $lName = $this->_getColName('left');
- $rName = $this->_getColName('right');
- $prevVisited = 0;
-
- // check the DB-table if the columns which are given as keys
- // in the array $newValues do really exist, if not remove them
- // from the array
- // FIXXME do the above described
- // if no parent and no prevId is given the root shall be added
- if ($parentId || $prevId) {
- if ($prevId) {
- $element = $this->getElement($prevId);
- // we also need the parent id of the element
- // to write it in the db
- $parentId = $element['parentId'];
- } else {
- $element = $this->getElement($parentId);
- }
- $newValues['parentId'] = $parentId;
-
- if (Tree::isError($element)) {
- return $element;
- }
-
- // get the "visited"-value where to add the new element behind
- // if $prevId is given, we need to use the right-value
- // if only the $parentId is given we need to use the left-value
- // look at it graphically, that made me understand it :-)
- // See:
- // http://research.calacademy.org/taf/proceedings/ballew/sld034.htm
- $prevVisited = $prevId ? $element['right'] : $element['left'];
-
- // FIXXME start transaction here
- if (Tree::isError($err = $this->_add($prevVisited, 1))) {
- // FIXXME rollback
- //$this->dbh->rollback();
- return $err;
- }
- }
-
- // inserting _one_ new element in the tree
- $newData = array();
- // quote the values, as needed for the insert
- foreach ($newValues as $key => $value) {
-
- ///////////FIX ME: Add proper quote handling
-
- $newData[$this->_getColName($key)] = $this->dbh->getTextValue($value);
- }
-
- // set the proper right and left values
- $newData[$lName] = $prevVisited + 1;
- $newData[$rName] = $prevVisited + 2;
-
- // use sequences to create a new id in the db-table
- $nextId = $this->dbh->nextId($this->table);
- $query = sprintf('INSERT INTO %s (%s,%s) VALUES (%s,%s)',
- $this->table,
- $this->_getColName('id'),
- implode(',', array_keys($newData)) ,
- $this->dbh->getIntegerValue($nextId),
- implode(',', $newData)
- );
- if (MDB::isError($res = $this->dbh->query($query))) {
- // rollback
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- // commit here
-
- return $nextId;
- }
-
- // }}}
- // {{{ _add()
-
- /**
- * this method only updates the left/right values of all the
- * elements that are affected by the insertion
- * be sure to set the parentId of the element(s) you insert
- *
- * @param int this parameter is not the ID!!!
- * it is the previous visit number, that means
- * if you are inserting a child, you need to use the left-value
- * of the parent
- * if you are inserting a "next" element, on the same level
- * you need to give the right value !!
- * @param int the number of elements you plan to insert
- * @return mixed either true on success or a Tree_Error on failure
- */
- function _add($prevVisited, $numberOfElements = 1)
- {
- $lName = $this->_getColName('left');
- $rName = $this->_getColName('right');
-
- // update the elements which will be affected by the new insert
- $query = sprintf('UPDATE %s SET %s=%s+%s WHERE%s %s>%s',
- $this->table,
- $lName,
- $lName,
- $numberOfElements*2,
- $this->_getWhereAddOn(),
- $lName,
- $prevVisited);
- if (MDB::isError($res = $this->dbh->query($query))) {
- // FIXXME rollback
- return $this->_throwError($res->getMessage(), __LINE__);
- }
-
- $query = sprintf('UPDATE %s SET %s=%s+%s WHERE%s %s>%s',
- $this->table,
- $rName,$rName,
- $numberOfElements*2,
- $this->_getWhereAddOn(),
- $rName,
- $prevVisited);
- if (MDB::isError($res = $this->dbh->query($query))) {
- // FIXXME rollback
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- return true;
- }
-
- // }}}
- // {{{ remove()
-
- /**
- * remove a tree element
- * this automatically remove all children and their children
- * if a node shall be removed that has children
- *
- * @access public
- * @param integer $id the id of the element to be removed
- * @return boolean returns either true or throws an error
- */
- function remove($id)
- {
- $element = $this->getElement($id);
- if (Tree::isError($element)) {
- return $element;
- }
-
- // FIXXME start transaction
- //$this->dbh->autoCommit(false);
- $query = sprintf( 'DELETE FROM %s WHERE%s %s BETWEEN %s AND %s',
- $this->table,
- $this->_getWhereAddOn(),
- $this->_getColName('left'),
- $element['left'],$element['right']);
- if (MDB::isError($res = $this->dbh->query($query))) {
- // FIXXME rollback
- //$this->dbh->rollback();
- return $this->_throwError($res->getMessage(), __LINE__);
- }
-
- if (Tree::isError($err = $this->_remove($element))) {
- // FIXXME rollback
- //$this->dbh->rollback();
- return $err;
- }
- return true;
- }
-
- // }}}
- // {{{ _remove()
-
- /**
- * removes a tree element, but only updates the left/right values
- * to make it seem as if the given element would not exist anymore
- * it doesnt remove the row(s) in the db itself!
- *
- * @see getElement()
- * @access private
- * @param array the entire element returned by "getElement"
- * @return boolean returns either true or throws an error
- */
- function _remove($element)
- {
- $delta = $element['right'] - $element['left'] + 1;
- $lName = $this->_getColName('left');
- $rName = $this->_getColName('right');
-
- // update the elements which will be affected by the remove
- $query = sprintf("UPDATE
- %s
- SET
- %s=%s-$delta,
- %s=%s-$delta
- WHERE%s %s>%s",
- $this->table,
- $lName, $lName,
- $rName, $rName,
- $this->_getWhereAddOn(),
- $lName, $element['left']);
- if (MDB::isError($res = $this->dbh->query($query))) {
- // the rollback shall be done by the method calling this one
- // since it is only private we can do that
- return $this->_throwError($res->getMessage(), __LINE__);
- }
-
- $query = sprintf("UPDATE
- %s
- SET %s=%s-$delta
- WHERE
- %s %s < %s
- AND
- %s>%s",
- $this->table,
- $rName, $rName,
- $this->_getWhereAddOn(),
- $lName, $element['left'],
- $rName, $element['right']);
- if (MDB::isError($res = $this->dbh->query($query))) {
- // the rollback shall be done by the method calling this one
- // since it is only private
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- // FIXXME commit:
- // should that not also be done in the method calling this one?
- // like when an error occurs?
- //$this->dbh->commit();
- return true;
- }
-
- // }}}
- // {{{ move()
-
- /**
- * move an entry under a given parent or behind a given entry.
- * If a newPrevId is given the newParentId is dismissed!
- * call it either like this:
- * $tree->move(x, y)
- * to move the element (or entire tree) with the id x
- * under the element with the id y
- * or
- * $tree->move(x, 0, y); // ommit the second parameter by setting
- * it to 0
- * to move the element (or entire tree) with the id x
- * behind the element with the id y
- * or
- * $tree->move(array(x1,x2,x3), ...
- * the first parameter can also be an array of elements that shall
- * be moved. the second and third para can be as described above.
- *
- * If you are using the Memory_DBnested then this method would be invain,
- * since Memory.php already does the looping through multiple elements.
- * But if Dynamic_DBnested is used we need to do the looping here
- *
- * @version 2002/06/08
- * @access public
- * @param integer the id(s) of the element(s) that shall be moved
- * @param integer the id of the element which will be the new parent
- * @param integer if prevId is given the element with the id idToMove
- * shall be moved _behind_ the element with id=prevId
- * if it is 0 it will be put at the beginning
- * @return mixed true for success, Tree_Error on failure
- */
- function move($idsToMove, $newParentId, $newPrevId = 0)
- {
- settype($idsToMove,'array');
- $errors = array();
- foreach ($idsToMove as $idToMove) {
- $ret = $this->_move($idToMove, $newParentId, $newPrevId);
- if (Tree::isError($ret)) {
- $errors[] = $ret;
- }
- }
- // FIXXME the error in a nicer way, or even better
- // let the throwError method do it!!!
- if (sizeof($errors)) {
- return $this->_throwError(serialize($errors), __LINE__);
- }
- return true;
- }
-
- // }}}
- // {{{ _move()
-
- /**
- * this method moves one tree element
- *
- * @see move()
- * @version 2002/04/29
- * @access public
- * @param integer the id of the element that shall be moved
- * @param integer the id of the element which will be the new parent
- * @param integer if prevId is given the element with the id idToMove
- * shall be moved _behind_ the element with id=prevId
- * if it is 0 it will be put at the beginning
- * @return mixed true for success, Tree_Error on failure
- */
- function _move($idToMove, $newParentId, $newPrevId = 0)
- {
- // do some integrity checks first
- if ($newPrevId) {
- // dont let people move an element behind itself, tell it
- // succeeded, since it already is there :-)
- if ($newPrevId == $idToMove) {
- return true;
- }
- if (Tree::isError($newPrevious=$this->getElement($newPrevId))) {
- return $newPrevious;
- }
- $newParentId = $newPrevious['parentId'];
- } else {
- if ($newParentId == 0) {
- return $this->_throwError('no parent id given', __LINE__);
- }
- // if the element shall be moved under one of its children
- // return false
- if ($this->isChildOf($idToMove,$newParentId)) {
- return $this->_throwError(
- 'can not move an element under one of its children' ,
- __LINE__
- );
- }
- // dont do anything to let an element be moved under itself
- // which is bullshit
- if ($newParentId==$idToMove) {
- return true;
- }
- // try to retreive the data of the parent element
- if (Tree::isError($newParent=$this->getElement($newParentId))) {
- return $newParent;
- }
- }
- // get the data of the element itself
- if (Tree::isError($element=$this->getElement($idToMove))) {
- return $element;
- }
-
- $numberOfElements = ($element['right'] - $element['left'] + 1) / 2;
- $prevVisited = $newPrevId ? $newPrevious['right'] : $newParent['left'];
-
- // FIXXME start transaction
-
- // add the left/right values in the new parent, to have the space
- // to move the new values in
- $err=$this->_add($prevVisited, $numberOfElements);
- if (Tree::isError($err)) {
- // FIXXME rollback
- //$this->dbh->rollback();
- return $err;
- }
-
- // update the parentId of the element with $idToMove
- $err = $this->update($idToMove, array('parentId' => $newParentId));
- if (Tree::isError($err)) {
- // FIXXME rollback
- //$this->dbh->rollback();
- return $err;
- }
-
- // update the lefts and rights of those elements that shall be moved
-
- // first get the offset we need to add to the left/right values
- // if $newPrevId is given we need to get the right value,
- // otherwise the left since the left/right has changed
- // because we already updated it up there. We need to get them again.
- // We have to do that anyway, to have the proper new left/right values
- if ($newPrevId) {
- if (Tree::isError($temp = $this->getElement($newPrevId))) {
- // FIXXME rollback
- //$this->dbh->rollback();
- return $temp;
- }
- $calcWith = $temp['right'];
- } else {
- if (Tree::isError($temp = $this->getElement($newParentId))) {
- // FIXXME rollback
- //$this->dbh->rollback();
- return $temp;
- }
- $calcWith = $temp['left'];
- }
-
- // get the element that shall be moved again, since the left and
- // right might have changed by the add-call
- if (Tree::isError($element=$this->getElement($idToMove))) {
- return $element;
- }
- // calc the offset that the element to move has
- // to the spot where it should go
- $offset = $calcWith - $element['left'];
- // correct the offset by one, since it needs to go inbetween!
- $offset++;
-
- $lName = $this->_getColName('left');
- $rName = $this->_getColName('right');
- $query = sprintf("UPDATE
- %s
- SET
- %s=%s+$offset,
- %s=%s+$offset
- WHERE
- %s %s>%s
- AND
- %s < %s",
- $this->table,
- $rName, $rName,
- $lName, $lName,
- $this->_getWhereAddOn(),
- $lName, $element['left']-1,
- $rName, $element['right']+1);
- if (MDB::isError($res=$this->dbh->query($query))) {
- // FIXXME rollback
- //$this->dbh->rollback();
- return $this->_throwError($res->getMessage(), __LINE__);
- }
-
- // remove the part of the tree where the element(s) was/were before
- if (Tree::isError($err=$this->_remove($element))) {
- // FIXXME rollback
- //$this->dbh->rollback();
- return $err;
- }
- // FIXXME commit all changes
- //$this->dbh->commit();
-
- return true;
- }
-
- // }}}
- // {{{ update()
-
- /**
- * update the tree element given by $id with the values in $newValues
- *
- * @access public
- * @param int the id of the element to update
- * @param array the new values, the index is the col name
- * @return mixed either true or an Tree_Error
- */
- function update($id, $newValues)
- {
- // just to be sure nothing gets screwed up :-)
- unset($newValues[$this->_getColName('left')]);
- unset($newValues[$this->_getColName('right')]);
- unset($newValues[$this->_getColName('parentId')]);
-
- // updating _one_ element in the tree
- $values = array();
- foreach ($newValues as $key=>$value) {
-
-
- ///////////FIX ME: Add proper quote handling
-
-
- $values[] = $this->_getColName($key).'='.$this->dbh->getTextValue($value);
- }
- $query = sprintf('UPDATE %s SET %s WHERE%s %s=%s',
- $this->table,
- implode(',',$values),
- $this->_getWhereAddOn(),
- $this->_getColName('id'),
- $id);
- if (MDB::isError($res=$this->dbh->query($query))) {
- return $this->_throwError($res->getMessage(), __LINE__);
- }
-
- return true;
- }
-
- // }}}
- // {{{ update()
-
- /**
- * copy a subtree/node/... under a new parent or/and behind a given element
- *
- *
- * @access public
- * @param integer the ID of the node that shall be copied
- * @param integer the new parent ID
- * @param integer the new previous ID, if given parent ID will be omitted
- * @return boolean true on success
- */
- function copy($id, $parentId = 0, $prevId = 0)
- {
- return $this->_throwError(
- 'copy-method is not implemented yet!' ,
- __LINE__
- );
- // get element tree
- // $this->addTree
- }
-
- // }}}
- // {{{ getRoot()
-
- /**
- * get the root
- *
- * @access public
- * @version 2002/03/02
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @return mixed either the data of the root element or an Tree_Error
- */
- function getRoot()
- {
- $query = sprintf('SELECT * FROM %s WHERE%s %s=1',
- $this->table,
- $this->_getWhereAddOn(),
- $this->_getColName('left'));
- if (MDB::isError($res = $this->dbh->getRow($query))) {
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- return !$res ? false : $this->_prepareResult($res);
- }
-
- // }}}
- // {{{ getElement()
-
- /**
- *
- *
- * @access public
- * @version 2002/03/02
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param integer the ID of the element to return
- *
- * @return mixed either the data of the requested element
- * or an Tree_Error
- */
- function getElement($id)
- {
- $query = sprintf('SELECT * FROM %s WHERE %s %s=%s',
- $this->table,
- $this->_getWhereAddOn(),
- $this->_getColName('id'),
- $id);
- if (MDB::isError($res = $this->dbh->getRow($query))) {
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- if (!$res) {
- return $this->_throwError("Element with id $id does not exist!" ,
- __LINE__);
- }
- return $this->_prepareResult($res);
- }
-
- // }}}
- // {{{ getChild()
-
- /**
- *
- *
- * @access public
- * @version 2002/03/02
- * @param integer the ID of the element for which the children
- * shall be returned
- * @return mixed either the data of the requested element or an Tree_Error
- */
- function getChild($id)
- {
- // subqueries would be cool :-)
- $curElement = $this->getElement($id);
- if (Tree::isError($curElement)) {
- return $curElement;
- }
-
- $query = sprintf('SELECT * FROM %s WHERE%s %s=%s',
- $this->table,
- $this->_getWhereAddOn(),
- $this->_getColName('left'),
- $curElement['left']+1);
- if (MDB::isError($res = $this->dbh->getRow($query))) {
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- return $this->_prepareResult($res);
- }
-
- // }}}
- // {{{ getPath()
-
- /**
- * gets the path from the element with the given id down
- * to the root. The returned array is sorted to start at root
- * for simply walking through and retreiving the path
- *
- * @access public
- * @param integer the ID of the element for which the path shall be returned
- * @return mixed either the data of the requested elements
- * or an Tree_Error
- */
- function getPath($id)
- {
- $res = $this->dbh->getAll($this->_getPathQuery($id));
- if (MDB::isError($res)) {
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- return $this->_prepareResults($res);
- }
-
- // }}}
- // {{{ _getPathQuery()
-
- function _getPathQuery($id)
- {
- // subqueries would be cool :-)
- $curElement = $this->getElement($id);
- $query = sprintf('SELECT * FROM %s '.
- 'WHERE %s %s<=%s AND %s>=%s '.
- 'ORDER BY %s',
- // set the FROM %s
- $this->table,
- // set the additional where add on
- $this->_getWhereAddOn(),
- // render 'left<=curLeft'
- $this->_getColName('left'), $curElement['left'],
- // render right>=curRight'
- $this->_getColName('right'), $curElement['right'],
- // set the order column
- $this->_getColName('left'));
- return $query;
- }
-
- // }}}
- // {{{ getLevel()
-
- function getLevel($id)
- {
- $query = $this->_getPathQuery($id);
- // i know this is not really beautiful ...
- $query = preg_replace('/^select \* /i','SELECT COUNT(*) ',$query);
- if (MDB::isError($res = $this->dbh->getOne($query))) {
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- return $res-1;
- }
-
- // }}}
- // {{{ getLeft()
-
- /**
- * gets the element to the left, the left visit
- *
- * @access public
- * @version 2002/03/07
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param integer the ID of the element
- * @return mixed either the data of the requested element
- * or an Tree_Error
- */
- function getLeft($id)
- {
- $element = $this->getElement($id);
- if (Tree::isError($element)) {
- return $element;
- }
-
- $query = sprintf('SELECT * FROM %s WHERE%s (%s=%s OR %s=%s)',
- $this->table,
- $this->_getWhereAddOn(),
- $this->_getColName('right'), $element['left'] - 1,
- $this->_getColName('left'), $element['left'] - 1);
- if (MDB::isError($res = $this->dbh->getRow($query))) {
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- return $this->_prepareResult($res);
- }
-
- // }}}
- // {{{ getRight()
-
- /**
- * gets the element to the right, the right visit
- *
- * @access public
- * @version 2002/03/07
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param integer the ID of the element
- * @return mixed either the data of the requested element
- * or an Tree_Error
- */
- function getRight($id)
- {
- $element = $this->getElement($id);
- if (Tree::isError($element))
- return $element;
-
- $query = sprintf('SELECT * FROM %s WHERE%s (%s=%s OR %s=%s)',
- $this->table,
- $this->_getWhereAddOn(),
- $this->_getColName('left'), $element['right'] + 1,
- $this->_getColName('right'), $element['right'] + 1);
- if (MDB::isError($res = $this->dbh->getRow($query))) {
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- return $this->_prepareResult($res);
- }
-
- // }}}
- // {{{ getParent()
-
- /**
- * get the parent of the element with the given id
- *
- * @access public
- * @version 2002/04/15
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param integer the ID of the element
- * @return mixed the array with the data of the parent element
- * or false, if there is no parent, if the element is
- * the root or an Tree_Error
- */
- function getParent($id)
- {
- $query = sprintf('SELECT
- p.*
- FROM
- %s p,%s e
- WHERE
- %s e.%s=p.%s
- AND
- e.%s=%s',
- $this->table,$this->table,
- $this->_getWhereAddOn(' AND ', 'p'),
- $this->_getColName('parentId'),
- $this->_getColName('id'),
- $this->_getColName('id'),
- $id);
- if (MDB::isError($res = $this->dbh->getRow($query))) {
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- return $this->_prepareResult($res);
- }
-
- // }}}
- // {{{ getChildren()
-
- /**
- * get the children of the given element or if the parameter is an array.
- * It gets the children of all the elements given by their ids
- * in the array.
- *
- * @access public
- * @version 2002/04/15
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param mixed (1) int the id of one element
- * (2) array an array of ids for which
- * the children will be returned
- * @param integer the children of how many levels shall be returned
- * @return mixed the array with the data of all children
- * or false, if there are none
- */
- function getChildren($ids, $levels = 1)
- {
- $res = array();
- for ($i = 1; $i < $levels + 1; $i++) {
- // if $ids is an array implode the values
- $getIds = is_array($ids) ? implode(',', $ids) : $ids;
-
- $query = sprintf('SELECT
- c.*
- FROM
- %s c,%s e
- WHERE
- %s e.%s=c.%s
- AND
- e.%s IN (%s) '.
- 'ORDER BY
- c.%s',
- $this->table,$this->table,
- $this->_getWhereAddOn(' AND ', 'c'),
- $this->_getColName('id'),
- $this->_getColName('parentId'),
- $this->_getColName('id'),
- $getIds,
- // order by left, so we have it in the order
- // as it is in the tree if no 'order'-option
- // is given
- $this->getOption('order')?
- $this->getOption('order')
- : $this->_getColName('left')
- );
- if (MDB::isError($_res = $this->dbh->getAll($query))) {
- return $this->_throwError($_res->getMessage(), __LINE__);
- }
-
- // Column names are now unmapped
- $_res = $this->_prepareResults($_res);
-
- // we use the id as the index, to make the use easier esp.
- // for multiple return-values
- $tempRes = array();
- foreach ($_res as $aRes) {
- $tempRes[$aRes['id']] = $aRes;
- }
- $_res = $tempRes;
-
- if ($levels > 1) {
- $ids = array();
- foreach ($_res as $aRes) {
- $ids[] = $aRes[$this->_getColName('id')];
- }
- }
- $res = array_merge($res, $_res);
-
- // quit the for-loop if there are no children in the current level
- if (!sizeof($ids)) {
- break;
- }
- }
- return $res;
- }
-
- // }}}
- // {{{ getNext()
-
- /**
- * get the next element on the same level
- * if there is none return false
- *
- * @access public
- * @version 2002/04/15
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param integer the ID of the element
- * @return mixed the array with the data of the next element
- * or false, if there is no next
- * or Tree_Error
- */
- function getNext($id)
- {
- $query = sprintf('SELECT
- n.*
- FROM
- %s n,%s e
- WHERE
- %s e.%s=n.%s-1
- AND
- e.%s=n.%s
- AND
- e.%s=%s',
- $this->table, $this->table,
- $this->_getWhereAddOn(' AND ', 'n'),
- $this->_getColName('right'),
- $this->_getColName('left'),
- $this->_getColName('parentId'),
- $this->_getColName('parentId'),
- $this->_getColName('id'),
- $id);
- if (MDB::isError($res = $this->dbh->getRow($query))) {
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- return !$res ? false : $this->_prepareResult($res);
- }
-
- // }}}
- // {{{ getPrevious()
-
- /**
- * get the previous element on the same level
- * if there is none return false
- *
- * @access public
- * @version 2002/04/15
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param integer the ID of the element
- * @return mixed the array with the data of the previous element
- * or false, if there is no previous
- * or a Tree_Error
- */
- function getPrevious($id)
- {
- $query = sprintf('SELECT
- p.*
- FROM
- %s p,%s e
- WHERE
- %s e.%s=p.%s+1
- AND
- e.%s=p.%s
- AND
- e.%s=%s',
- $this->table,$this->table,
- $this->_getWhereAddOn(' AND ', 'p'),
- $this->_getColName('left'),
- $this->_getColName('right'),
- $this->_getColName('parentId'),
- $this->_getColName('parentId'),
- $this->_getColName('id'),
- $id);
- if (MDB::isError($res = $this->dbh->getRow($query))) {
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- return !$res ? false : $this->_prepareResult($res);
- }
-
- // }}}
- // {{{ isChildOf()
-
- /**
- * returns if $childId is a child of $id
- *
- * @abstract
- * @version 2002/04/29
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param int id of the element
- * @param int id of the element to check if it is a child
- * @return boolean true if it is a child
- */
- function isChildOf($id, $childId)
- {
- // check simply if the left and right of the child are within the
- // left and right of the parent, if so it definitly is a child :-)
- $parent = $this->getElement($id);
- $child = $this->getElement($childId);
-
- if ($parent['left'] < $child['left']
- && $parent['right'] > $child['right'])
- {
- return true;
- }
- return false;
- }
-
- // }}}
- // {{{ getDepth()
-
- /**
- * return the maximum depth of the tree
- *
- * @version 2003/02/25
- * @access public
- * @author "Denis Joloudov" <dan@aitart.ru>, Wolfram Kriesing <wolfram@kriesing.de>
- * @return integer the depth of the tree
- */
- function getDepth()
- {
- // FIXXXME TODO!!!
- $query = sprintf('SELECT COUNT(*) FROM %s p, %s e '.
- 'WHERE %s (e.%s BETWEEN p.%s AND p.%s) AND '.
- '(e.%s BETWEEN p.%s AND p.%s)',
- $this-> table,$this->table,
- // first line in where
- $this->_getWhereAddOn(' AND ','p'),
- $this->_getColName('left'),$this->_getColName('left'),
- $this->_getColName('right'),
- // second where line
- $this->_getColName('right'),$this->_getColName('left'),
- $this->_getColName('right')
- );
- if (MDB::isError($res=$this->dbh->getOne($query))) {
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- if (!$res) {
- return false;
- }
- return $this->_prepareResult($res);
- }
-
- // }}}
- // {{{ hasChildren()
-
- /**
- * Tells if the node with the given ID has children.
- *
- * @version 2003/03/04
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param integer the ID of a node
- * @return boolean if the node with the given id has children
- */
- function hasChildren($id)
- {
- $element = $this->getElement($id);
- // if the diff between left and right > 1 then there are children
- return ($element['right'] - $element['left']) > 1;
- }
-
- // }}}
- // {{{ getIdByPath()
-
- /**
- * return the id of the element which is referenced by $path
- * this is useful for xml-structures, like: getIdByPath('/root/sub1/sub2')
- * this requires the structure to use each name uniquely
- * if this is not given it will return the first proper path found
- * i.e. there should only be one path /x/y/z
- * experimental: the name can be non unique if same names are in different levels
- *
- * @version 2003/05/11
- * @access public
- * @author Pierre-Alain Joye <paj@pearfr.org>
- * @param string $path the path to search for
- * @param integer $startId the id where to start the search
- * @param string $nodeName the name of the key that contains
- * the node name
- * @param string $seperator the path seperator
- * @return integer the id of the searched element
- */
- function getIdByPath($path, $startId = 0, $nodeName = 'name', $separator = '/')
- // should this method be called getElementIdByPath ????
- // Yes, with an optional private paramater to get the whole node
- // in preference to only the id?
- {
- if ($separator == '') {
- return $this->_throwError(
- 'getIdByPath: Empty separator not allowed', __LINE__);
- }
- if ($path == $separator) {
- $root = $this->getRoot();
- if (Tree::isError($root)) {
- return $root;
- }
- return $root['id'];
- }
- if (!($colname=$this->_getColName($nodeName))) {
- return $this->_throwError(
- 'getIdByPath: Invalid node name', __LINE__);
- }
- if ($startId != 0) {
- // If the start node has no child, returns false
- // hasChildren calls getElement. Not very good right
- // now. See the TODO
- $startElem = $this->getElement($startId);
- if (!is_array($startElem) || Tree::isError($startElem)) {
- return $startElem;
- }
- // No child? return
- if (!is_array($startElem)) {
- return null;
- }
- $rangeStart = $startElem['left'];
- $rangeEnd = $startElem['right'];
- // Not clean, we should call hasChildren, but I do not
- // want to call getELement again :). See TODO
- $startHasChild = ($rangeEnd-$rangeStart) > 1 ? true : false;
- $cwd = '/'.$this->getPathAsString($startId);
- } else {
- $cwd = '/';
- $startHasChild = false;
- }
- $t = $this->_preparePath($path, $cwd, $separator);
- if (Tree::isError($t)) {
- return $t;
- }
- list($elems, $sublevels) = $t;
- $cntElems = sizeof($elems);
- $where = '';
-
- $query = 'SELECT '
- .$this->_getColName('id')
- .' FROM '
- .$this->table
- .' WHERE '
- .$colname;
- if ($cntElems == 1) {
- $query .= "='".$elems[0]."'";
- } else {
- $query .= "='".$elems[$cntElems-1]."'";
- }
- if ($startHasChild) {
- $where .= ' AND ('.
- $this->_getColName('left').'>'.$rangeStart.
- ' AND '.
- $this->_getColName('right').'<'.$rangeEnd.')';
- }
- $res = $this->dbh->getOne($query);
- if (MDB::isError($res)) {
- return $this->_throwError($res->getMessage(),
- __LINE__);
- }
- return ($res ? (int)$res : false);
- }
-
- // }}}
-
- //
- // PRIVATE METHODS
- //
-
- // {{{ _getWhereAddOn()
- /**
- *
- *
- * @access private
- * @version 2002/04/20
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param string the current where clause
- * @return string the where clause we want to add to a query
- */
- function _getWhereAddOn($addAfter = ' AND ', $tableName = '')
- {
- if ($where=$this->getOption('whereAddOn')) {
- return ' '.($tableName ? $tableName.'.' : '')." $where$addAfter ";
- }
- return '';
- }
-
- // }}}
- // {{{ getFirstRoot()
-
- // for compatibility to Memory methods
- function getFirstRoot()
- {
- return $this->getRoot();
- }
-
- // }}}
- // {{{ getNode()
-
- /**
- * gets the tree under the given element in one array, sorted
- * so you can go through the elements from begin to end and list them
- * as they are in the tree, where every child (until the deepest) is retreived
- *
- * @see &_getNode()
- * @access public
- * @version 2001/12/17
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param integer $startId the id where to start walking
- * @param integer $depth this number says how deep into
- * the structure the elements shall
- * be retreived
- * @return array sorted as listed in the tree
- */
- function &getNode($startId = 0, $depth = 0)
- {
-//FIXXXME use getChildren()
- if ($startId) {
- $startNode = $this->getElement($startId);
- if (Tree::isError($startNode)) {
- return $startNode;
- }
-
- } else {
- }
- }
-}
-
-/*
-* Local Variables:
-* mode: php
-* tab-width: 4
-* c-basic-offset: 4
-* End:
-*/
\ No newline at end of file
Index: Tree/Dynamic/MDB2nested.php
===================================================================
--- Tree/Dynamic/MDB2nested.php (.../branches/Tree_0_3_0) (revision 321102)
+++ Tree/Dynamic/MDB2nested.php (.../trunk) (revision 321102)
@@ -1,1281 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4: */
-// +----------------------------------------------------------------------+
-// | PHP Version 4 |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2004 The PHP Group |
-// +----------------------------------------------------------------------+
-// | This source file is subject to version 2.02 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: |
-// +----------------------------------------------------------------------+
-//
-// $Id$
-
-require_once 'Tree/OptionsMDB2.php';
-
-/**
-* This class implements methods to work on a tree saved using the nested
-* tree model.
-* explaination: http://research.calacademy.org/taf/proceedings/ballew/index.htm
-*
-* @access public
-* @package Tree
-*/
-class Tree_Dynamic_MDB2nested extends Tree_OptionsMDB2
-{
-
- // {{{ properties
- var $debug = 0;
-
- var $options = array(
- // FIXXME to be implemented
- // add on for the where clause, this string is simply added
- // behind the WHERE in the select so you better make sure
- // its correct SQL :-), i.e. 'uid=3'
- // this is needed i.e. when you are saving many trees in one db-table
- 'whereAddOn'=>'',
- 'table' =>'',
- // since the internal names are fixed, to be portable between different
- // DB tables with different column namings, we map the internal name
- // to the real column name using this array here, if it stays empty
- // the internal names are used, which are:
- // id, left, right
- 'columnNameMaps'=>array(
- // since mysql at least doesnt support 'left' ...
- 'left' => 'l',
- // ...as a column name we set default to the first
- //letter only
- 'right' => 'r',
- // parent id
- 'parentId' => 'parent'
- ),
- // needed for sorting the tree, currently only used in Memory_DBnested
- 'order' => ''
- );
-
- // }}}
- // {{{ __construct()
-
- // the defined methods here are proposals for the implementation,
- // they are named the same, as the methods in the "Memory" branch.
- // If possible it would be cool to keep the same naming. And
- // if the same parameters would be possible too then it would be
- // even better, so one could easily change from any kind
- // of tree-implementation to another, without changing the source
- // code, only the setupXXX would need to be changed
- /**
- *
- *
- * @access public
- * @version 2002/03/02
- * @param string the DSN for the DB connection
- * @return void
- */
- function __construct($dsn, $options = array())
- {
- $this->Tree_Dynamic_MDB2nested($dsn, $options);
- }
-
- // }}}
- // {{{ Tree_Dynamic_DBnested()
-
- /**
- *
- *
- * @access public
- * @version 2002/03/02
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param string the DSN for the DB connection
- * @return void
- */
- function Tree_Dynamic_MDB2nested($dsn, $options = array())
- {
- parent::Tree_OptionsMDB2($dsn, $options); // instanciate DB
- $this->table = $this->getOption('table');
- }
-
- // }}}
- // {{{ add()
-
- /**
- * add a new element to the tree
- * there are three ways to use this method
- * Method 1:
- * Give only the $parentId and the $newValues will be inserted
- * as the first child of this parent
- * <code>
- * // insert a new element under the parent with the ID=7
- * $tree->add(array('name'=>'new element name'), 7);
- * </code>
- *
- * Method 2:
- * Give the $prevId ($parentId will be dismissed) and the new element
- * will be inserted in the tree after the element with the ID=$prevId
- * the parentId is not necessary because the prevId defines exactly where
- * the new element has to be place in the tree, and the parent is
- * the same as for the element with the ID=$prevId
- * <code>
- * // insert a new element after the element with the ID=5
- * $tree->add(array('name'=>'new'), 0, 5);
- * </code>
- *
- * Method 3:
- * neither $parentId nor prevId is given, then the root element will be
- * inserted. This requires that programmer is responsible to confirm this.
- * This method does not yet check if there is already a root element saved!
- *
- * @access public
- * @param array $newValues this array contains the values that shall
- * be inserted in the db-table
- * @param integer $parentId the id of the element which shall be
- * the parent of the new element
- * @param integer $prevId the id of the element which shall preceed
- * the one to be inserted use either
- * 'parentId' or 'prevId'.
- * @return integer the ID of the element that had been inserted
- */
- function add($newValues, $parentId = 0, $prevId = 0)
- {
- $lName = $this->_getColName('left');
- $rName = $this->_getColName('right');
- $prevVisited = 0;
-
- // check the DB-table if the columns which are given as keys
- // in the array $newValues do really exist, if not remove them
- // from the array
- // FIXXME do the above described
- // if no parent and no prevId is given the root shall be added
- if ($parentId || $prevId) {
- if ($prevId) {
- $element = $this->getElement($prevId);
- // we also need the parent id of the element
- // to write it in the db
- $parentId = $element['parentId'];
- } else {
- $element = $this->getElement($parentId);
- }
- $newValues['parentId'] = $parentId;
-
- if (Tree::isError($element)) {
- return $element;
- }
-
- // get the "visited"-value where to add the new element behind
- // if $prevId is given, we need to use the right-value
- // if only the $parentId is given we need to use the left-value
- // look at it graphically, that made me understand it :-)
- // See:
- // http://research.calacademy.org/taf/proceedings/ballew/sld034.htm
- $prevVisited = $prevId ? $element['right'] : $element['left'];
-
- // FIXXME start transaction here
- if (Tree::isError($err = $this->_add($prevVisited, 1))) {
- // FIXXME rollback
- //$this->dbh->rollback();
- return $err;
- }
- }
-
- // inserting _one_ new element in the tree
- $newData = array();
- // quote the values, as needed for the insert
- foreach ($newValues as $key => $value) {
-
- ///////////FIX ME: Add proper quote handling
-
- $newData[$this->_getColName($key)] = $this->dbh->quote($value, 'text');
- }
-
- // set the proper right and left values
- $newData[$lName] = $prevVisited + 1;
- $newData[$rName] = $prevVisited + 2;
-
- // use sequences to create a new id in the db-table
- $nextId = $this->dbh->nextId($this->table);
- $query = sprintf('INSERT INTO %s (%s,%s) VALUES (%s,%s)',
- $this->table,
- $this->_getColName('id'),
- implode(',', array_keys($newData)) ,
- $this->dbh->quote($nextId, 'integer'),
- implode(',', $newData)
- );
- if (MDB2::isError($res = $this->dbh->exec($query))) {
- // rollback
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- // commit here
-
- return $nextId;
- }
-
- // }}}
- // {{{ _add()
-
- /**
- * this method only updates the left/right values of all the
- * elements that are affected by the insertion
- * be sure to set the parentId of the element(s) you insert
- *
- * @param int this parameter is not the ID!!!
- * it is the previous visit number, that means
- * if you are inserting a child, you need to use the left-value
- * of the parent
- * if you are inserting a "next" element, on the same level
- * you need to give the right value !!
- * @param int the number of elements you plan to insert
- * @return mixed either true on success or a Tree_Error on failure
- */
- function _add($prevVisited, $numberOfElements = 1)
- {
- $lName = $this->_getColName('left');
- $rName = $this->_getColName('right');
-
- // update the elements which will be affected by the new insert
- $query = sprintf('UPDATE %s SET %s=%s+%s WHERE%s %s>%s',
- $this->table,
- $lName,
- $lName,
- $numberOfElements*2,
- $this->_getWhereAddOn(),
- $lName,
- $prevVisited);
- if (MDB2::isError($res = $this->dbh->exec($query))) {
- // FIXXME rollback
- return $this->_throwError($res->getMessage(), __LINE__);
- }
-
- $query = sprintf('UPDATE %s SET %s=%s+%s WHERE%s %s>%s',
- $this->table,
- $rName,$rName,
- $numberOfElements*2,
- $this->_getWhereAddOn(),
- $rName,
- $prevVisited);
- if (MDB2::isError($res = $this->dbh->exec($query))) {
- // FIXXME rollback
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- return true;
- }
-
- // }}}
- // {{{ remove()
-
- /**
- * remove a tree element
- * this automatically remove all children and their children
- * if a node shall be removed that has children
- *
- * @access public
- * @param integer $id the id of the element to be removed
- * @return boolean returns either true or throws an error
- */
- function remove($id)
- {
- $element = $this->getElement($id);
- if (Tree::isError($element)) {
- return $element;
- }
-
- // FIXXME start transaction
- //$this->dbh->autoCommit(false);
- $query = sprintf( 'DELETE FROM %s WHERE%s %s BETWEEN %s AND %s',
- $this->table,
- $this->_getWhereAddOn(),
- $this->_getColName('left'),
- $element['left'],$element['right']);
- if (MDB2::isError($res = $this->dbh->exec($query))) {
- // FIXXME rollback
- //$this->dbh->rollback();
- return $this->_throwError($res->getMessage(), __LINE__);
- }
-
- if (Tree::isError($err = $this->_remove($element))) {
- // FIXXME rollback
- //$this->dbh->rollback();
- return $err;
- }
- return true;
- }
-
- // }}}
- // {{{ _remove()
-
- /**
- * removes a tree element, but only updates the left/right values
- * to make it seem as if the given element would not exist anymore
- * it doesnt remove the row(s) in the db itself!
- *
- * @see getElement()
- * @access private
- * @param array the entire element returned by "getElement"
- * @return boolean returns either true or throws an error
- */
- function _remove($element)
- {
- $delta = $element['right'] - $element['left'] + 1;
- $lName = $this->_getColName('left');
- $rName = $this->_getColName('right');
-
- // update the elements which will be affected by the remove
- $query = sprintf("UPDATE
- %s
- SET
- %s=%s-$delta,
- %s=%s-$delta
- WHERE%s %s>%s",
- $this->table,
- $lName, $lName,
- $rName, $rName,
- $this->_getWhereAddOn(),
- $lName, $element['left']);
- if (MDB2::isError($res = $this->dbh->exec($query))) {
- // the rollback shall be done by the method calling this one
- // since it is only private we can do that
- return $this->_throwError($res->getMessage(), __LINE__);
- }
-
- $query = sprintf("UPDATE
- %s
- SET %s=%s-$delta
- WHERE
- %s %s < %s
- AND
- %s>%s",
- $this->table,
- $rName, $rName,
- $this->_getWhereAddOn(),
- $lName, $element['left'],
- $rName, $element['right']);
- if (MDB2::isError($res = $this->dbh->exec($query))) {
- // the rollback shall be done by the method calling this one
- // since it is only private
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- // FIXXME commit:
- // should that not also be done in the method calling this one?
- // like when an error occurs?
- //$this->dbh->commit();
- return true;
- }
-
- // }}}
- // {{{ move()
-
- /**
- * move an entry under a given parent or behind a given entry.
- * If a newPrevId is given the newParentId is dismissed!
- * call it either like this:
- * $tree->move(x, y)
- * to move the element (or entire tree) with the id x
- * under the element with the id y
- * or
- * $tree->move(x, 0, y); // ommit the second parameter by setting
- * it to 0
- * to move the element (or entire tree) with the id x
- * behind the element with the id y
- * or
- * $tree->move(array(x1,x2,x3), ...
- * the first parameter can also be an array of elements that shall
- * be moved. the second and third para can be as described above.
- *
- * If you are using the Memory_DBnested then this method would be invain,
- * since Memory.php already does the looping through multiple elements.
- * But if Dynamic_DBnested is used we need to do the looping here
- *
- * @version 2002/06/08
- * @access public
- * @param integer the id(s) of the element(s) that shall be moved
- * @param integer the id of the element which will be the new parent
- * @param integer if prevId is given the element with the id idToMove
- * shall be moved _behind_ the element with id=prevId
- * if it is 0 it will be put at the beginning
- * @return mixed true for success, Tree_Error on failure
- */
- function move($idsToMove, $newParentId, $newPrevId = 0)
- {
- settype($idsToMove,'array');
- $errors = array();
- foreach ($idsToMove as $idToMove) {
- $ret = $this->_move($idToMove, $newParentId, $newPrevId);
- if (Tree::isError($ret)) {
- $errors[] = $ret;
- }
- }
- // FIXXME the error in a nicer way, or even better
- // let the throwError method do it!!!
- if (sizeof($errors)) {
- return $this->_throwError(serialize($errors), __LINE__);
- }
- return true;
- }
-
- // }}}
- // {{{ _move()
-
- /**
- * this method moves one tree element
- *
- * @see move()
- * @version 2002/04/29
- * @access public
- * @param integer the id of the element that shall be moved
- * @param integer the id of the element which will be the new parent
- * @param integer if prevId is given the element with the id idToMove
- * shall be moved _behind_ the element with id=prevId
- * if it is 0 it will be put at the beginning
- * @return mixed true for success, Tree_Error on failure
- */
- function _move($idToMove, $newParentId, $newPrevId = 0)
- {
- // do some integrity checks first
- if ($newPrevId) {
- // dont let people move an element behind itself, tell it
- // succeeded, since it already is there :-)
- if ($newPrevId == $idToMove) {
- return true;
- }
- if (Tree::isError($newPrevious=$this->getElement($newPrevId))) {
- return $newPrevious;
- }
- $newParentId = $newPrevious['parentId'];
- } else {
- if ($newParentId == 0) {
- return $this->_throwError('no parent id given', __LINE__);
- }
- // if the element shall be moved under one of its children
- // return false
- if ($this->isChildOf($idToMove,$newParentId)) {
- return $this->_throwError(
- 'can not move an element under one of its children',
- __LINE__
- );
- }
- // dont do anything to let an element be moved under itself
- // which is bullshit
- if ($newParentId==$idToMove) {
- return true;
- }
- // try to retreive the data of the parent element
- if (Tree::isError($newParent = $this->getElement($newParentId))) {
- return $newParent;
- }
- }
- // get the data of the element itself
- if (Tree::isError($element = $this->getElement($idToMove))) {
- return $element;
- }
-
- $numberOfElements = ($element['right'] - $element['left'] + 1) / 2;
- $prevVisited = $newPrevId ? $newPrevious['right'] : $newParent['left'];
-
- // FIXXME start transaction
-
- // add the left/right values in the new parent, to have the space
- // to move the new values in
- $err=$this->_add($prevVisited, $numberOfElements);
- if (Tree::isError($err)) {
- // FIXXME rollback
- //$this->dbh->rollback();
- return $err;
- }
-
- // update the parentId of the element with $idToMove
- $err = $this->update($idToMove, array('parentId' => $newParentId));
- if (Tree::isError($err)) {
- // FIXXME rollback
- //$this->dbh->rollback();
- return $err;
- }
-
- // update the lefts and rights of those elements that shall be moved
-
- // first get the offset we need to add to the left/right values
- // if $newPrevId is given we need to get the right value,
- // otherwise the left since the left/right has changed
- // because we already updated it up there. We need to get them again.
- // We have to do that anyway, to have the proper new left/right values
- if ($newPrevId) {
- if (Tree::isError($temp = $this->getElement($newPrevId))) {
- // FIXXME rollback
- //$this->dbh->rollback();
- return $temp;
- }
- $calcWith = $temp['right'];
- } else {
- if (Tree::isError($temp = $this->getElement($newParentId))) {
- // FIXXME rollback
- //$this->dbh->rollback();
- return $temp;
- }
- $calcWith = $temp['left'];
- }
-
- // get the element that shall be moved again, since the left and
- // right might have changed by the add-call
- if (Tree::isError($element = $this->getElement($idToMove))) {
- return $element;
- }
- // calc the offset that the element to move has
- // to the spot where it should go
- $offset = $calcWith - $element['left'];
- // correct the offset by one, since it needs to go inbetween!
- $offset++;
-
- $lName = $this->_getColName('left');
- $rName = $this->_getColName('right');
- $query = sprintf("UPDATE
- %s
- SET
- %s=%s+$offset,
- %s=%s+$offset
- WHERE
- %s %s>%s
- AND
- %s < %s",
- $this->table,
- $rName, $rName,
- $lName, $lName,
- $this->_getWhereAddOn(),
- $lName, $element['left']-1,
- $rName, $element['right']+1);
- if (MDB2::isError($res = $this->dbh->exec($query))) {
- // FIXXME rollback
- //$this->dbh->rollback();
- return $this->_throwError($res->getMessage(), __LINE__);
- }
-
- // remove the part of the tree where the element(s) was/were before
- if (Tree::isError($err = $this->_remove($element))) {
- // FIXXME rollback
- //$this->dbh->rollback();
- return $err;
- }
- // FIXXME commit all changes
- //$this->dbh->commit();
-
- return true;
- }
-
- // }}}
- // {{{ update()
-
- /**
- * update the tree element given by $id with the values in $newValues
- *
- * @access public
- * @param int the id of the element to update
- * @param array the new values, the index is the col name
- * @return mixed either true or an Tree_Error
- */
- function update($id, $newValues)
- {
- // just to be sure nothing gets screwed up :-)
- unset($newValues[$this->_getColName('left')]);
- unset($newValues[$this->_getColName('right')]);
- unset($newValues[$this->_getColName('parentId')]);
-
- // updating _one_ element in the tree
- $values = array();
- foreach ($newValues as $key=>$value) {
-
-
- ///////////FIX ME: Add proper quote handling
-
-
- $values[] = $this->_getColName($key).'='.$this->dbh->quote($value, 'text');
- }
- $query = sprintf('UPDATE %s SET %s WHERE%s %s=%s',
- $this->table,
- implode(',',$values),
- $this->_getWhereAddOn(),
- $this->_getColName('id'),
- $id);
- if (MDB2::isError($res = $this->dbh->exec($query))) {
- return $this->_throwError($res->getMessage(), __LINE__);
- }
-
- return true;
- }
-
- // }}}
- // {{{ update()
-
- /**
- * copy a subtree/node/... under a new parent or/and behind a given element
- *
- *
- * @access public
- * @param integer the ID of the node that shall be copied
- * @param integer the new parent ID
- * @param integer the new previous ID, if given parent ID will be omitted
- * @return boolean true on success
- */
- function copy($id, $parentId = 0, $prevId = 0)
- {
- return $this->_throwError(
- 'copy-method is not implemented yet!',
- __LINE__
- );
- // get element tree
- // $this->addTree
- }
-
- // }}}
- // {{{ getRoot()
-
- /**
- * get the root
- *
- * @access public
- * @version 2002/03/02
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @return mixed either the data of the root element or an Tree_Error
- */
- function getRoot()
- {
- $query = sprintf('SELECT * FROM %s WHERE%s %s=1',
- $this->table,
- $this->_getWhereAddOn(),
- $this->_getColName('left'));
- if (MDB2::isError($res = $this->dbh->queryRow($query))) {
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- return !$res ? false : $this->_prepareResult($res);
- }
-
- // }}}
- // {{{ getElement()
-
- /**
- *
- *
- * @access public
- * @version 2002/03/02
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param integer the ID of the element to return
- *
- * @return mixed either the data of the requested element
- * or an Tree_Error
- */
- function getElement($id)
- {
- $query = sprintf('SELECT * FROM %s WHERE %s %s=%s',
- $this->table,
- $this->_getWhereAddOn(),
- $this->_getColName('id'),
- $id);
- if (MDB2::isError($res = $this->dbh->queryRow($query))) {
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- if (!$res) {
- return $this->_throwError("Element with id $id does not exist!", __LINE__);
- }
- return $this->_prepareResult($res);
- }
-
- // }}}
- // {{{ getChild()
-
- /**
- *
- *
- * @access public
- * @version 2002/03/02
- * @param integer the ID of the element for which the children
- * shall be returned
- * @return mixed either the data of the requested element or an Tree_Error
- */
- function getChild($id)
- {
- // subqueries would be cool :-)
- $curElement = $this->getElement($id);
- if (Tree::isError($curElement)) {
- return $curElement;
- }
-
- $query = sprintf('SELECT * FROM %s WHERE%s %s=%s',
- $this->table,
- $this->_getWhereAddOn(),
- $this->_getColName('left'),
- $curElement['left']+1);
- if (MDB2::isError($res = $this->dbh->queryRow($query))) {
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- return $this->_prepareResult($res);
- }
-
- // }}}
- // {{{ getPath()
-
- /**
- * gets the path from the element with the given id down
- * to the root. The returned array is sorted to start at root
- * for simply walking through and retreiving the path
- *
- * @access public
- * @param integer the ID of the element for which the path shall be returned
- * @return mixed either the data of the requested elements
- * or an Tree_Error
- */
- function getPath($id)
- {
- $res = $this->dbh->queryAll($this->_getPathQuery($id));
- if (MDB2::isError($res)) {
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- return $this->_prepareResults($res);
- }
-
- // }}}
- // {{{ _getPathQuery()
-
- function _getPathQuery($id)
- {
- // subqueries would be cool :-)
- $curElement = $this->getElement($id);
- $query = sprintf('SELECT * FROM %s '.
- 'WHERE %s %s<=%s AND %s>=%s '.
- 'ORDER BY %s',
- // set the FROM %s
- $this->table,
- // set the additional where add on
- $this->_getWhereAddOn(),
- // render 'left<=curLeft'
- $this->_getColName('left'), $curElement['left'],
- // render right>=curRight'
- $this->_getColName('right'), $curElement['right'],
- // set the order column
- $this->_getColName('left'));
- return $query;
- }
-
- // }}}
- // {{{ getLevel()
-
- function getLevel($id)
- {
- $query = $this->_getPathQuery($id);
- // i know this is not really beautiful ...
- $query = preg_replace('/^select \* /i','SELECT COUNT(*) ',$query);
- if (MDB2::isError($res = $this->dbh->queryOne($query))) {
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- return $res-1;
- }
-
- // }}}
- // {{{ getLeft()
-
- /**
- * gets the element to the left, the left visit
- *
- * @access public
- * @version 2002/03/07
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param integer the ID of the element
- * @return mixed either the data of the requested element
- * or an Tree_Error
- */
- function getLeft($id)
- {
- $element = $this->getElement($id);
- if (Tree::isError($element)) {
- return $element;
- }
-
- $query = sprintf('SELECT * FROM %s WHERE%s (%s=%s OR %s=%s)',
- $this->table,
- $this->_getWhereAddOn(),
- $this->_getColName('right'), $element['left'] - 1,
- $this->_getColName('left'), $element['left'] - 1);
- if (MDB2::isError($res = $this->dbh->queryRow($query))) {
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- return $this->_prepareResult($res);
- }
-
- // }}}
- // {{{ getRight()
-
- /**
- * gets the element to the right, the right visit
- *
- * @access public
- * @version 2002/03/07
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param integer the ID of the element
- * @return mixed either the data of the requested element
- * or an Tree_Error
- */
- function getRight($id)
- {
- $element = $this->getElement($id);
- if (Tree::isError($element))
- return $element;
-
- $query = sprintf('SELECT * FROM %s WHERE%s (%s=%s OR %s=%s)',
- $this->table,
- $this->_getWhereAddOn(),
- $this->_getColName('left'), $element['right'] + 1,
- $this->_getColName('right'), $element['right'] + 1);
- if (MDB2::isError($res = $this->dbh->queryRow($query))) {
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- return $this->_prepareResult($res);
- }
-
- // }}}
- // {{{ getParent()
-
- /**
- * get the parent of the element with the given id
- *
- * @access public
- * @version 2002/04/15
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param integer the ID of the element
- * @return mixed the array with the data of the parent element
- * or false, if there is no parent, if the element is
- * the root or an Tree_Error
- */
- function getParent($id)
- {
- $query = sprintf('SELECT
- p.*
- FROM
- %s p,%s e
- WHERE
- %s e.%s=p.%s
- AND
- e.%s=%s',
- $this->table,$this->table,
- $this->_getWhereAddOn(' AND ', 'p'),
- $this->_getColName('parentId'),
- $this->_getColName('id'),
- $this->_getColName('id'),
- $id);
- if (MDB2::isError($res = $this->dbh->queryRow($query))) {
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- return $this->_prepareResult($res);
- }
-
- // }}}
- // {{{ getChildren()
-
- /**
- * get the children of the given element or if the parameter is an array.
- * It gets the children of all the elements given by their ids
- * in the array.
- *
- * @access public
- * @version 2002/04/15
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param mixed (1) int the id of one element
- * (2) array an array of ids for which
- * the children will be returned
- * @param integer the children of how many levels shall be returned
- * @return mixed the array with the data of all children
- * or false, if there are none
- */
- function getChildren($ids, $levels = 1)
- {
- $res = array();
- for ($i = 1; $i < $levels + 1; $i++) {
- // if $ids is an array implode the values
- $getIds = is_array($ids) ? implode(',', $ids) : $ids;
-
- $query = sprintf('SELECT
- c.*
- FROM
- %s c,%s e
- WHERE
- %s e.%s=c.%s
- AND
- e.%s IN (%s) '.
- 'ORDER BY
- c.%s',
- $this->table,$this->table,
- $this->_getWhereAddOn(' AND ', 'c'),
- $this->_getColName('id'),
- $this->_getColName('parentId'),
- $this->_getColName('id'),
- $getIds,
- // order by left, so we have it in the order
- // as it is in the tree if no 'order'-option
- // is given
- $this->getOption('order')?
- $this->getOption('order')
- : $this->_getColName('left')
- );
- if (MDB2::isError($_res = $this->dbh->queryAll($query))) {
- return $this->_throwError($_res->getMessage(), __LINE__);
- }
-
- // Column names are now unmapped
- $_res = $this->_prepareResults($_res);
-
- // we use the id as the index, to make the use easier esp.
- // for multiple return-values
- $tempRes = array();
- foreach ($_res as $aRes) {
- $tempRes[$aRes['id']] = $aRes;
- }
- $_res = $tempRes;
-
- if ($levels > 1) {
- $ids = array();
- foreach ($_res as $aRes) {
- $ids[] = $aRes[$this->_getColName('id')];
- }
- }
- $res = array_merge($res, $_res);
-
- // quit the for-loop if there are no children in the current level
- if (!sizeof($ids)) {
- break;
- }
- }
- return $res;
- }
-
- // }}}
- // {{{ getNext()
-
- /**
- * get the next element on the same level
- * if there is none return false
- *
- * @access public
- * @version 2002/04/15
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param integer the ID of the element
- * @return mixed the array with the data of the next element
- * or false, if there is no next
- * or Tree_Error
- */
- function getNext($id)
- {
- $query = sprintf('SELECT
- n.*
- FROM
- %s n,%s e
- WHERE
- %s e.%s=n.%s-1
- AND
- e.%s=n.%s
- AND
- e.%s=%s',
- $this->table, $this->table,
- $this->_getWhereAddOn(' AND ', 'n'),
- $this->_getColName('right'),
- $this->_getColName('left'),
- $this->_getColName('parentId'),
- $this->_getColName('parentId'),
- $this->_getColName('id'),
- $id);
- if (MDB2::isError($res = $this->dbh->queryRow($query))) {
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- return !$res ? false : $this->_prepareResult($res);
- }
-
- // }}}
- // {{{ getPrevious()
-
- /**
- * get the previous element on the same level
- * if there is none return false
- *
- * @access public
- * @version 2002/04/15
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param integer the ID of the element
- * @return mixed the array with the data of the previous element
- * or false, if there is no previous
- * or a Tree_Error
- */
- function getPrevious($id)
- {
- $query = sprintf('SELECT
- p.*
- FROM
- %s p,%s e
- WHERE
- %s e.%s=p.%s+1
- AND
- e.%s=p.%s
- AND
- e.%s=%s',
- $this->table,$this->table,
- $this->_getWhereAddOn(' AND ', 'p'),
- $this->_getColName('left'),
- $this->_getColName('right'),
- $this->_getColName('parentId'),
- $this->_getColName('parentId'),
- $this->_getColName('id'),
- $id);
- if (MDB2::isError($res = $this->dbh->queryRow($query))) {
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- return !$res ? false : $this->_prepareResult($res);
- }
-
- // }}}
- // {{{ isChildOf()
-
- /**
- * returns if $childId is a child of $id
- *
- * @abstract
- * @version 2002/04/29
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param int id of the element
- * @param int id of the element to check if it is a child
- * @return boolean true if it is a child
- */
- function isChildOf($id, $childId)
- {
- // check simply if the left and right of the child are within the
- // left and right of the parent, if so it definitly is a child :-)
- $parent = $this->getElement($id);
- $child = $this->getElement($childId);
-
- if ($parent['left'] < $child['left']
- && $parent['right'] > $child['right'])
- {
- return true;
- }
- return false;
- }
-
- // }}}
- // {{{ getDepth()
-
- /**
- * return the maximum depth of the tree
- *
- * @version 2003/02/25
- * @access public
- * @author "Denis Joloudov" <dan@aitart.ru>, Wolfram Kriesing <wolfram@kriesing.de>
- * @return integer the depth of the tree
- */
- function getDepth()
- {
- // FIXXXME TODO!!!
- $query = sprintf('SELECT COUNT(*) FROM %s p, %s e '.
- 'WHERE %s (e.%s BETWEEN p.%s AND p.%s) AND '.
- '(e.%s BETWEEN p.%s AND p.%s)',
- $this-> table,$this->table,
- // first line in where
- $this->_getWhereAddOn(' AND ','p'),
- $this->_getColName('left'),$this->_getColName('left'),
- $this->_getColName('right'),
- // second where line
- $this->_getColName('right'),$this->_getColName('left'),
- $this->_getColName('right')
- );
- if (MDB2::isError($res=$this->dbh->queryOne($query))) {
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- if (!$res) {
- return false;
- }
- return $this->_prepareResult($res);
- }
-
- // }}}
- // {{{ hasChildren()
-
- /**
- * Tells if the node with the given ID has children.
- *
- * @version 2003/03/04
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param integer the ID of a node
- * @return boolean if the node with the given id has children
- */
- function hasChildren($id)
- {
- $element = $this->getElement($id);
- // if the diff between left and right > 1 then there are children
- return ($element['right'] - $element['left']) > 1;
- }
-
- // }}}
- // {{{ getIdByPath()
-
- /**
- * return the id of the element which is referenced by $path
- * this is useful for xml-structures, like: getIdByPath('/root/sub1/sub2')
- * this requires the structure to use each name uniquely
- * if this is not given it will return the first proper path found
- * i.e. there should only be one path /x/y/z
- * experimental: the name can be non unique if same names are in different levels
- *
- * @version 2003/05/11
- * @access public
- * @author Pierre-Alain Joye <paj@pearfr.org>
- * @param string $path the path to search for
- * @param integer $startId the id where to start the search
- * @param string $nodeName the name of the key that contains
- * the node name
- * @param string $seperator the path seperator
- * @return integer the id of the searched element
- */
- function getIdByPath($path, $startId = 0, $nodeName = 'name', $separator = '/')
- // should this method be called getElementIdByPath ????
- // Yes, with an optional private paramater to get the whole node
- // in preference to only the id?
- {
- if ($separator == '') {
- return $this->_throwError(
- 'getIdByPath: Empty separator not allowed', __LINE__);
- }
- if ($path == $separator) {
- $root = $this->getRoot();
- if (Tree::isError($root)) {
- return $root;
- }
- return $root['id'];
- }
- if (!($colname=$this->_getColName($nodeName))) {
- return $this->_throwError(
- 'getIdByPath: Invalid node name', __LINE__);
- }
- if ($startId != 0) {
- // If the start node has no child, returns false
- // hasChildren calls getElement. Not very good right
- // now. See the TODO
- $startElem = $this->getElement($startId);
- if (!is_array($startElem) || Tree::isError($startElem)) {
- return $startElem;
- }
- // No child? return
- if (!is_array($startElem)) {
- return null;
- }
- $rangeStart = $startElem['left'];
- $rangeEnd = $startElem['right'];
- // Not clean, we should call hasChildren, but I do not
- // want to call getELement again :). See TODO
- $startHasChild = ($rangeEnd-$rangeStart) > 1 ? true : false;
- $cwd = '/'.$this->getPathAsString($startId);
- } else {
- $cwd = '/';
- $startHasChild = false;
- }
- $t = $this->_preparePath($path, $cwd, $separator);
- if (Tree::isError($t)) {
- return $t;
- }
- list($elems, $sublevels) = $t;
- $cntElems = sizeof($elems);
- $where = '';
-
- $query = 'SELECT '
- .$this->_getColName('id')
- .' FROM '
- .$this->table
- .' WHERE '
- .$colname;
- if ($cntElems == 1) {
- $query .= "='".$elems[0]."'";
- } else {
- $query .= "='".$elems[$cntElems-1]."'";
- }
- if ($startHasChild) {
- $where .= ' AND ('.
- $this->_getColName('left').'>'.$rangeStart.
- ' AND '.
- $this->_getColName('right').'<'.$rangeEnd.')';
- }
- $res = $this->dbh->queryOne($query);
- if (MDB2::isError($res)) {
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- return ($res ? (int)$res : false);
- }
-
- // }}}
-
- //
- // PRIVATE METHODS
- //
-
- // {{{ _getWhereAddOn()
- /**
- *
- *
- * @access private
- * @version 2002/04/20
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param string the current where clause
- * @return string the where clause we want to add to a query
- */
- function _getWhereAddOn($addAfter = ' AND ', $tableName = '')
- {
- if ($where=$this->getOption('whereAddOn')) {
- return ' '.($tableName ? $tableName.'.' : '')." $where$addAfter ";
- }
- return '';
- }
-
- // }}}
- // {{{ getFirstRoot()
-
- // for compatibility to Memory methods
- function getFirstRoot()
- {
- return $this->getRoot();
- }
-
- // }}}
- // {{{ getNode()
-
- /**
- * gets the tree under the given element in one array, sorted
- * so you can go through the elements from begin to end and list them
- * as they are in the tree, where every child (until the deepest) is retreived
- *
- * @see &_getNode()
- * @access public
- * @version 2001/12/17
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param integer $startId the id where to start walking
- * @param integer $depth this number says how deep into
- * the structure the elements shall
- * be retreived
- * @return array sorted as listed in the tree
- */
- function &getNode($startId = 0, $depth = 0)
- {
-//FIXXXME use getChildren()
- if ($startId) {
- $startNode = $this->getElement($startId);
- if (Tree::isError($startNode)) {
- return $startNode;
- }
-
- } else {
- }
- }
-}
-
-/*
-* Local Variables:
-* mode: php
-* tab-width: 4
-* c-basic-offset: 4
-* End:
-*/
\ No newline at end of file
Index: Tree/Dynamic/DBnested.php
===================================================================
--- Tree/Dynamic/DBnested.php (.../branches/Tree_0_3_0) (revision 321102)
+++ Tree/Dynamic/DBnested.php (.../trunk) (revision 321102)
@@ -1,1287 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4: */
-// +----------------------------------------------------------------------+
-// | PHP Version 4 |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2003 The PHP Group |
-// +----------------------------------------------------------------------+
-// | This source file is subject to version 2.02 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: |
-// +----------------------------------------------------------------------+
-//
-// $Id$
-
-require_once 'Tree/OptionsDB.php';
-
-/**
- * This class implements methods to work on a tree saved using the nested
- * tree model.
- * explaination: http://research.calacademy.org/taf/proceedings/ballew/index.htm
- *
- * @access public
- * @package Tree
- */
-class Tree_Dynamic_DBnested extends Tree_OptionsDB
-{
-
- // {{{ properties
- var $debug = 0;
-
- var $options = array(
- // FIXXME to be implemented
- // add on for the where clause, this string is simply added
- // behind the WHERE in the select so you better make sure
- // its correct SQL :-), i.e. 'uid=3'
- // this is needed i.e. when you are saving many trees in one db-table
- 'whereAddOn'=>'',
- 'table' =>'',
- // since the internal names are fixed, to be portable between different
- // DB tables with different column namings, we map the internal name
- // to the real column name using this array here, if it stays empty
- // the internal names are used, which are:
- // id, left, right
- 'columnNameMaps'=>array(
- // since mysql at least doesnt support 'left' ...
- 'left' => 'l',
- // ...as a column name we set default to the first
- //letter only
- 'right' => 'r',
- // parent id
- 'parentId' => 'parent'
- ),
- // needed for sorting the tree, currently only used in Memory_DBnested
- 'order' => ''
- );
-
- // }}}
- // {{{ __construct()
-
- // the defined methods here are proposals for the implementation,
- // they are named the same, as the methods in the "Memory" branch.
- // If possible it would be cool to keep the same naming. And
- // if the same parameters would be possible too then it would be
- // even better, so one could easily change from any kind
- // of tree-implementation to another, without changing the source
- // code, only the setupXXX would need to be changed
- /**
- *
- *
- * @access public
- * @version 2002/03/02
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param string the DSN for the DB connection
- * @return void
- */
- function __construct($dsn, $options = array())
- {
- $this->Tree_Dynamic_DBnested($dsn, $options);
- }
-
- // }}}
- // {{{ Tree_Dynamic_DBnested()
-
- /**
- *
- *
- * @access public
- * @version 2002/03/02
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param string the DSN for the DB connection
- * @return void
- */
- function Tree_Dynamic_DBnested($dsn, $options = array())
- {
- parent::Tree_OptionsDB($dsn, $options); // instanciate DB
- $this->table = $this->getOption('table');
- }
-
- // }}}
- // {{{ add()
-
- /**
- * add a new element to the tree
- * there are three ways to use this method
- * Method 1:
- * Give only the $parentId and the $newValues will be inserted
- * as the first child of this parent
- * <code>
- * // insert a new element under the parent with the ID=7
- * $tree->add(array('name'=>'new element name'), 7);
- * </code>
- *
- * Method 2:
- * Give the $prevId ($parentId will be dismissed) and the new element
- * will be inserted in the tree after the element with the ID=$prevId
- * the parentId is not necessary because the prevId defines exactly where
- * the new element has to be place in the tree, and the parent is
- * the same as for the element with the ID=$prevId
- * <code>
- * // insert a new element after the element with the ID=5
- * $tree->add(array('name'=>'new'), 0, 5);
- * </code>
- *
- * Method 3:
- * neither $parentId nor prevId is given, then the root element will be
- * inserted. This requires that programmer is responsible to confirm this.
- * This method does not yet check if there is already a root element saved!
- *
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param array $newValues this array contains the values that shall
- * be inserted in the db-table
- * @param integer $parentId the id of the element which shall be
- * the parent of the new element
- * @param integer $prevId the id of the element which shall preceed
- * the one to be inserted use either
- * 'parentId' or 'prevId'.
- * @return integer the ID of the element that had been inserted
- */
- function add($newValues, $parentId = 0, $prevId = 0)
- {
- $lName = $this->_getColName('left');
- $rName = $this->_getColName('right');
- $prevVisited = 0;
-
- // check the DB-table if the columns which are given as keys
- // in the array $newValues do really exist, if not remove them
- // from the array
- // FIXXME do the above described
- // if no parent and no prevId is given the root shall be added
- if ($parentId || $prevId) {
- if ($prevId) {
- $element = $this->getElement($prevId);
- // we also need the parent id of the element
- // to write it in the db
- $parentId = $element['parentId'];
- } else {
- $element = $this->getElement($parentId);
- }
- $newValues['parentId'] = $parentId;
-
- if (Tree::isError($element)) {
- return $element;
- }
-
- // get the "visited"-value where to add the new element behind
- // if $prevId is given, we need to use the right-value
- // if only the $parentId is given we need to use the left-value
- // look at it graphically, that made me understand it :-)
- // See:
- // http://research.calacademy.org/taf/proceedings/ballew/sld034.htm
- $prevVisited = $prevId ? $element['right'] : $element['left'];
-
- // FIXXME start transaction here
- if (Tree::isError($err = $this->_add($prevVisited, 1))) {
- // FIXXME rollback
- //$this->dbh->rollback();
- return $err;
- }
- }
-
- // inserting _one_ new element in the tree
- $newData = array();
- // quote the values, as needed for the insert
- foreach ($newValues as $key => $value) {
- $newData[$this->_getColName($key)] = $this->dbh->quoteSmart($value);
- }
-
- // set the proper right and left values
- $newData[$lName] = $prevVisited + 1;
- $newData[$rName] = $prevVisited + 2;
-
- // use sequences to create a new id in the db-table
- $nextId = $this->dbh->nextId($this->table);
- $query = sprintf('INSERT INTO %s (%s,%s) VALUES (%s,%s)',
- $this->table ,
- $this->_getColName('id'),
- implode(',', array_keys($newData)) ,
- $nextId,
- implode(',', $newData)
- );
- if (DB::isError($res = $this->dbh->query($query))) {
- // rollback
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- // commit here
-
- return $nextId;
- }
-
- // }}}
- // {{{ _add()
-
- /**
- * this method only updates the left/right values of all the
- * elements that are affected by the insertion
- * be sure to set the parentId of the element(s) you insert
- *
- * @param int this parameter is not the ID!!!
- * it is the previous visit number, that means
- * if you are inserting a child, you need to use the left-value
- * of the parent
- * if you are inserting a "next" element, on the same level
- * you need to give the right value !!
- * @param int the number of elements you plan to insert
- * @return mixed either true on success or a Tree_Error on failure
- */
- function _add($prevVisited, $numberOfElements = 1)
- {
- $lName = $this->_getColName('left');
- $rName = $this->_getColName('right');
-
- // update the elements which will be affected by the new insert
- $query = sprintf('UPDATE %s SET %s=%s+%s WHERE%s %s>%s',
- $this->table,
- $lName,
- $lName,
- $numberOfElements*2,
- $this->_getWhereAddOn(),
- $lName,
- $prevVisited);
- if (DB::isError($res = $this->dbh->query($query))) {
- // FIXXME rollback
- return $this->_throwError($res->getMessage(), __LINE__);
- }
-
- $query = sprintf('UPDATE %s SET %s=%s+%s WHERE%s %s>%s',
- $this->table,
- $rName,$rName,
- $numberOfElements*2,
- $this->_getWhereAddOn(),
- $rName,
- $prevVisited);
- if (DB::isError($res = $this->dbh->query($query))) {
- // FIXXME rollback
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- return true;
- }
-
- // }}}
- // {{{ remove()
-
- /**
- * remove a tree element
- * this automatically remove all children and their children
- * if a node shall be removed that has children
- *
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param integer $id the id of the element to be removed
- * @return boolean returns either true or throws an error
- */
- function remove($id)
- {
- $element = $this->getElement($id);
- if (Tree::isError($element)) {
- return $element;
- }
-
- // FIXXME start transaction
- //$this->dbh->autoCommit(false);
- $query = sprintf('DELETE FROM %s WHERE%s %s BETWEEN %s AND %s',
- $this->table,
- $this->_getWhereAddOn(),
- $this->_getColName('left'),
- $element['left'],$element['right']);
- if (DB::isError($res = $this->dbh->query($query))) {
- // FIXXME rollback
- //$this->dbh->rollback();
- return $this->_throwError($res->getMessage(), __LINE__);
- }
-
- if (Tree::isError($err = $this->_remove($element))) {
- // FIXXME rollback
- //$this->dbh->rollback();
- return $err;
- }
- return true;
- }
-
- // }}}
- // {{{ _remove()
-
- /**
- * removes a tree element, but only updates the left/right values
- * to make it seem as if the given element would not exist anymore
- * it doesnt remove the row(s) in the db itself!
- *
- * @see getElement()
- * @access private
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param array the entire element returned by "getElement"
- * @return boolean returns either true or throws an error
- */
- function _remove($element)
- {
- $delta = $element['right'] - $element['left'] + 1;
- $lName = $this->_getColName('left');
- $rName = $this->_getColName('right');
-
- // update the elements which will be affected by the remove
- $query = sprintf("UPDATE
- %s
- SET
- %s=%s-$delta,
- %s=%s-$delta
- WHERE%s %s>%s",
- $this->table,
- $lName,$lName,
- $rName,$rName,
- $this->_getWhereAddOn(),
- $lName,$element['left']);
- if (DB::isError($res = $this->dbh->query($query))) {
- // the rollback shall be done by the method calling this one
- // since it is only private we can do that
- return $this->_throwError($res->getMessage(), __LINE__);
- }
-
- $query = sprintf("UPDATE
- %s
- SET %s=%s-$delta
- WHERE
- %s %s < %s
- AND
- %s>%s",
- $this->table,
- $rName,$rName,
- $this->_getWhereAddOn(),
- $lName,$element['left'],
- $rName,$element['right']);
- if (DB::isError($res = $this->dbh->query($query))) {
- // the rollback shall be done by the method calling this one
- // since it is only private
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- // FIXXME commit:
- // should that not also be done in the method calling this one?
- // like when an error occurs?
- //$this->dbh->commit();
- return true;
- }
-
- // }}}
- // {{{ move()
-
- /**
- * move an entry under a given parent or behind a given entry.
- * If a newPrevId is given the newParentId is dismissed!
- * call it either like this:
- * $tree->move(x, y)
- * to move the element (or entire tree) with the id x
- * under the element with the id y
- * or
- * $tree->move(x, 0, y); // ommit the second parameter by setting
- * it to 0
- * to move the element (or entire tree) with the id x
- * behind the element with the id y
- * or
- * $tree->move(array(x1,x2,x3), ...
- * the first parameter can also be an array of elements that shall
- * be moved. the second and third para can be as described above.
- *
- * If you are using the Memory_DBnested then this method would be invain,
- * since Memory.php already does the looping through multiple elements.
- * But if Dynamic_DBnested is used we need to do the looping here
- *
- * @version 2002/06/08
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param integer the id(s) of the element(s) that shall be moved
- * @param integer the id of the element which will be the new parent
- * @param integer if prevId is given the element with the id idToMove
- * shall be moved _behind_ the element with id=prevId
- * if it is 0 it will be put at the beginning
- * @return mixed true for success, Tree_Error on failure
- */
- function move($idsToMove, $newParentId, $newPrevId = 0)
- {
- settype($idsToMove, 'array');
- $errors = array();
- foreach ($idsToMove as $idToMove) {
- $ret = $this->_move($idToMove, $newParentId, $newPrevId);
- if (Tree::isError($ret)) {
- $errors[] = $ret;
- }
- }
- // FIXXME the error in a nicer way, or even better
- // let the throwError method do it!!!
- if (sizeof($errors)) {
- return $this->_throwError(serialize($errors), __LINE__);
- }
- return true;
- }
-
- // }}}
- // {{{ _move()
-
- /**
- * this method moves one tree element
- *
- * @see move()
- * @version 2002/04/29
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param integer the id of the element that shall be moved
- * @param integer the id of the element which will be the new parent
- * @param integer if prevId is given the element with the id idToMove
- * shall be moved _behind_ the element with id=prevId
- * if it is 0 it will be put at the beginning
- * @return mixed true for success, Tree_Error on failure
- */
- function _move($idToMove, $newParentId, $newPrevId = 0)
- {
- // do some integrity checks first
- if ($newPrevId) {
- // dont let people move an element behind itself, tell it
- // succeeded, since it already is there :-)
- if ($newPrevId == $idToMove) {
- return true;
- }
- if (Tree::isError($newPrevious = $this->getElement($newPrevId))) {
- return $newPrevious;
- }
- $newParentId = $newPrevious['parentId'];
- } else {
- if ($newParentId == 0) {
- return $this->_throwError('no parent id given', __LINE__);
- }
- // if the element shall be moved under one of its children
- // return false
- if ($this->isChildOf($idToMove,$newParentId)) {
- return $this->_throwError(
- 'can not move an element under one of its children' ,
- __LINE__
- );
- }
- // dont do anything to let an element be moved under itself
- // which is bullshit
- if ($newParentId == $idToMove) {
- return true;
- }
- // try to retreive the data of the parent element
- if (Tree::isError($newParent=$this->getElement($newParentId))) {
- return $newParent;
- }
- }
- // get the data of the element itself
- if (Tree::isError($element=$this->getElement($idToMove))) {
- return $element;
- }
-
- $numberOfElements = ($element['right'] - $element['left'] + 1) / 2;
- $prevVisited = $newPrevId ? $newPrevious['right'] : $newParent['left'];
-
- // FIXXME start transaction
-
- // add the left/right values in the new parent, to have the space
- // to move the new values in
- $err = $this->_add($prevVisited, $numberOfElements);
- if (Tree::isError($err)) {
- // FIXXME rollback
- //$this->dbh->rollback();
- return $err;
- }
-
- // update the parentId of the element with $idToMove
- $err = $this->update($idToMove,array('parentId' => $newParentId));
- if (Tree::isError($err)) {
- // FIXXME rollback
- //$this->dbh->rollback();
- return $err;
- }
-
- // update the lefts and rights of those elements that shall be moved
-
- // first get the offset we need to add to the left/right values
- // if $newPrevId is given we need to get the right value,
- // otherwise the left since the left/right has changed
- // because we already updated it up there. We need to get them again.
- // We have to do that anyway, to have the proper new left/right values
- if ($newPrevId) {
- if (Tree::isError($temp = $this->getElement($newPrevId))) {
- // FIXXME rollback
- //$this->dbh->rollback();
- return $temp;
- }
- $calcWith = $temp['right'];
- } else {
- if (Tree::isError($temp=$this->getElement($newParentId))) {
- // FIXXME rollback
- //$this->dbh->rollback();
- return $temp;
- }
- $calcWith = $temp['left'];
- }
-
- // get the element that shall be moved again, since the left and
- // right might have changed by the add-call
- if (Tree::isError($element=$this->getElement($idToMove))) {
- return $element;
- }
- // calc the offset that the element to move has
- // to the spot where it should go
- $offset = $calcWith - $element['left'];
- // correct the offset by one, since it needs to go inbetween!
- $offset++;
-
- $lName = $this->_getColName('left');
- $rName = $this->_getColName('right');
- $query = sprintf("UPDATE
- %s
- SET
- %s=%s+$offset,
- %s=%s+$offset
- WHERE
- %s %s>%s
- AND
- %s < %s",
- $this->table,
- $rName,$rName,
- $lName,$lName,
- $this->_getWhereAddOn(),
- $lName,$element['left']-1,
- $rName,$element['right']+1);
- if (DB::isError($res=$this->dbh->query($query))) {
- // FIXXME rollback
- //$this->dbh->rollback();
- return $this->_throwError($res->getMessage(), __LINE__);
- }
-
- // remove the part of the tree where the element(s) was/were before
- if (Tree::isError($err = $this->_remove($element))) {
- // FIXXME rollback
- //$this->dbh->rollback();
- return $err;
- }
- // FIXXME commit all changes
- //$this->dbh->commit();
-
- return true;
- }
-
- // }}}
- // {{{ update()
-
- /**
- * update the tree element given by $id with the values in $newValues
- *
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param int the id of the element to update
- * @param array the new values, the index is the col name
- * @return mixed either true or an Tree_Error
- */
- function update($id, $newValues)
- {
- // just to be sure nothing gets screwed up :-)
- unset($newValues[$this->_getColName('left')]);
- unset($newValues[$this->_getColName('right')]);
- unset($newValues[$this->_getColName('parentId')]);
-
- // updating _one_ element in the tree
- $values = array();
- foreach ($newValues as $key => $value) {
- $values[] = $this->_getColName($key).'='.$this->dbh->quoteSmart($value);
- }
- $query = sprintf('UPDATE %s SET %s WHERE%s %s=%s',
- $this->table,
- implode(',',$values),
- $this->_getWhereAddOn(),
- $this->_getColName('id'),
- $id);
- if (DB::isError($res=$this->dbh->query($query))) {
- return $this->_throwError($res->getMessage(), __LINE__);
- }
-
- return true;
- }
-
- // }}}
- // {{{ update()
-
- /**
- * copy a subtree/node/... under a new parent or/and behind a given element
- *
- *
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param integer the ID of the node that shall be copied
- * @param integer the new parent ID
- * @param integer the new previous ID, if given parent ID will be omitted
- * @return boolean true on success
- */
- function copy($id, $parentId = 0, $prevId = 0)
- {
- return $this->_throwError(
- 'copy-method is not implemented yet!' ,
- __LINE__
- );
- // get element tree
- // $this->addTree
- }
-
- // }}}
- // {{{ getRoot()
-
- /**
- * get the root
- *
- * @access public
- * @version 2002/03/02
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @return mixed either the data of the root element or an Tree_Error
- */
- function getRoot()
- {
- $query = sprintf('SELECT * FROM %s WHERE%s %s=1',
- $this->table,
- $this->_getWhereAddOn(),
- $this->_getColName('left'));
- if (DB::isError($res = $this->dbh->getRow($query))) {
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- return !$res ? false : $this->_prepareResult($res);
- }
-
- // }}}
- // {{{ getElement()
-
- /**
- *
- *
- * @access public
- * @version 2002/03/02
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param integer the ID of the element to return
- *
- * @return mixed either the data of the requested element
- * or an Tree_Error
- */
- function getElement($id)
- {
- $query = sprintf('SELECT * FROM %s WHERE %s %s=%s',
- $this->table,
- $this->_getWhereAddOn(),
- $this->_getColName('id'),
- $id);
- $res = $this->dbh->getRow($query);
- if (DB::isError($res)) {
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- if (!$res) {
- return $this->_throwError("Element with id $id does not exist!" ,
- __LINE__);
- }
- return $this->_prepareResult($res);
- }
-
- // }}}
- // {{{ getChild()
-
- /**
- *
- *
- * @access public
- * @version 2002/03/02
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param integer the ID of the element for which the children
- * shall be returned
- * @return mixed either the data of the requested element or an Tree_Error
- */
- function getChild($id)
- {
- // subqueries would be cool :-)
- $curElement = $this->getElement($id);
- if (Tree::isError($curElement)) {
- return $curElement;
- }
-
- $query = sprintf('SELECT * FROM %s WHERE%s %s=%s',
- $this->table,
- $this->_getWhereAddOn(),
- $this->_getColName('left'),
- $curElement['left']+1);
- if (DB::isError($res = $this->dbh->getRow($query))) {
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- return $this->_prepareResult($res);
- }
-
- // }}}
- // {{{ getPath()
-
- /**
- * gets the path from the element with the given id down
- * to the root. The returned array is sorted to start at root
- * for simply walking through and retreiving the path
- *
- * @access public
- * @version 2002/03/02
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param integer the ID of the element for which the path shall be
- * returned
- * @return mixed either the data of the requested elements
- * or an Tree_Error
- */
- function getPath($id)
- {
- $res = $this->dbh->getAll($this->_getPathQuery($id));
- if (DB::isError($res)) {
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- return $this->_prepareResults($res);
- }
-
- // }}}
- // {{{ _getPathQuery()
-
- function _getPathQuery($id)
- {
- // subqueries would be cool :-)
- $curElement = $this->getElement($id);
- $query = sprintf('SELECT * FROM %s '.
- 'WHERE %s %s<=%s AND %s>=%s '.
- 'ORDER BY %s',
- // set the FROM %s
- $this->table,
- // set the additional where add on
- $this->_getWhereAddOn(),
- // render 'left<=curLeft'
- $this->_getColName('left'),$curElement['left'],
- // render right>=curRight'
- $this->_getColName('right'),$curElement['right'],
- // set the order column
- $this->_getColName('left'));
- return $query;
- }
-
- // }}}
- // {{{ getLevel()
-
- function getLevel($id)
- {
- $query = $this->_getPathQuery($id);
- // i know this is not really beautiful ...
- $query = preg_replace('/^select \* /i','SELECT COUNT(*) ',$query);
- if (DB::isError($res = $this->dbh->getOne($query))) {
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- return $res-1;
- }
-
- // }}}
- // {{{ getLeft()
-
- /**
- * gets the element to the left, the left visit
- *
- * @access public
- * @version 2002/03/07
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param integer the ID of the element
- * @return mixed either the data of the requested element
- * or an Tree_Error
- */
- function getLeft($id)
- {
- $element = $this->getElement($id);
- if (Tree::isError($element)) {
- return $element;
- }
-
- $query = sprintf('SELECT * FROM %s WHERE%s (%s=%s OR %s=%s)',
- $this->table,
- $this->_getWhereAddOn(),
- $this->_getColName('right'),$element['left']-1,
- $this->_getColName('left'),$element['left']-1);
- if (DB::isError($res = $this->dbh->getRow($query))) {
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- return $this->_prepareResult($res);
- }
-
- // }}}
- // {{{ getRight()
-
- /**
- * gets the element to the right, the right visit
- *
- * @access public
- * @version 2002/03/07
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param integer the ID of the element
- * @return mixed either the data of the requested element
- * or an Tree_Error
- */
- function getRight($id)
- {
- $element = $this->getElement($id);
- if (Tree::isError($element)) {
- return $element;
- }
- $query = sprintf('SELECT * FROM %s WHERE%s (%s=%s OR %s=%s)',
- $this->table,
- $this->_getWhereAddOn(),
- $this->_getColName('left'),$element['right']+1,
- $this->_getColName('right'),$element['right']+1);
- if (DB::isError($res = $this->dbh->getRow($query))) {
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- return $this->_prepareResult($res);
- }
-
- // }}}
- // {{{ getParent()
-
- /**
- * get the parent of the element with the given id
- *
- * @access public
- * @version 2002/04/15
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param integer the ID of the element
- * @return mixed the array with the data of the parent element
- * or false, if there is no parent, if the element is
- * the root or an Tree_Error
- */
- function getParent($id)
- {
- $query = sprintf('SELECT
- p.*
- FROM
- %s p,%s e
- WHERE
- %s e.%s=p.%s
- AND
- e.%s=%s',
- $this->table,$this->table,
- $this->_getWhereAddOn(' AND ', 'p'),
- $this->_getColName('parentId'),
- $this->_getColName('id'),
- $this->_getColName('id'),
- $id);
- if (DB::isError($res = $this->dbh->getRow($query))) {
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- return $this->_prepareResult($res);
- }
-
- // }}}
- // {{{ getChildren()
-
- /**
- * get the children of the given element or if the parameter is an array.
- * It gets the children of all the elements given by their ids
- * in the array.
- *
- * @access public
- * @version 2002/04/15
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param mixed (1) int the id of one element
- * (2) array an array of ids for which
- * the children will be returned
- * @param integer the children of how many levels shall be returned
- * @return mixed the array with the data of all children
- * or false, if there are none
- */
- function getChildren($ids, $levels = 1)
- {
- $res = array();
- for ($i = 1; $i < $levels + 1; $i++) {
- // if $ids is an array implode the values
- $getIds = is_array($ids) ? implode(',',$ids) : $ids;
-
- $query = sprintf('SELECT
- c.*
- FROM
- %s c,%s e
- WHERE
- %s e.%s=c.%s
- AND
- e.%s IN (%s) '.
- 'ORDER BY
- c.%s',
- $this->table,$this->table,
- $this->_getWhereAddOn(' AND ', 'c'),
- $this->_getColName('id'),
- $this->_getColName('parentId'),
- $this->_getColName('id'),
- $getIds,
- // order by left, so we have it in the order
- // as it is in the tree if no 'order'-option
- // is given
- $this->getOption('order')?
- $this->getOption('order')
- : $this->_getColName('left')
- );
- if (DB::isError($_res = $this->dbh->getAll($query))) {
- return $this->_throwError($_res->getMessage(), __LINE__);
- }
-
- // Column names are now unmapped
- $_res = $this->_prepareResults($_res);
-
- // we use the id as the index, to make the use easier esp.
- // for multiple return-values
- $tempRes = array();
- foreach ($_res as $aRes) {
- $tempRes[$aRes['id']] = $aRes;
- }
- $_res = $tempRes;
-
- if ($levels>1) {
- $ids = array();
- foreach($_res as $aRes) {
- $ids[] = $aRes[$this->_getColName('id')];
- }
- }
- $res = array_merge($res,$_res);
-
- // quit the for-loop if there are no children in the current level
- if (!sizeof($ids)) {
- break;
- }
- }
- return $res;
- }
-
- // }}}
- // {{{ getNext()
-
- /**
- * get the next element on the same level
- * if there is none return false
- *
- * @access public
- * @version 2002/04/15
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param integer the ID of the element
- * @return mixed the array with the data of the next element
- * or false, if there is no next
- * or Tree_Error
- */
- function getNext($id)
- {
- $query = sprintf('SELECT
- n.*
- FROM
- %s n,%s e
- WHERE
- %s e.%s=n.%s-1
- AND
- e.%s=n.%s
- AND
- e.%s=%s',
- $this->table,$this->table,
- $this->_getWhereAddOn(' AND ', 'n'),
- $this->_getColName('right'),
- $this->_getColName('left'),
- $this->_getColName('parentId'),
- $this->_getColName('parentId'),
- $this->_getColName('id'),
- $id);
- if (DB::isError($res = $this->dbh->getRow($query))) {
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- return !$res ? false : $this->_prepareResult($res);
- }
-
- // }}}
- // {{{ getPrevious()
-
- /**
- * get the previous element on the same level
- * if there is none return false
- *
- * @access public
- * @version 2002/04/15
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param integer the ID of the element
- * @return mixed the array with the data of the previous element
- * or false, if there is no previous
- * or a Tree_Error
- */
- function getPrevious($id)
- {
- $query = sprintf('SELECT
- p.*
- FROM
- %s p,%s e
- WHERE
- %s e.%s=p.%s+1
- AND
- e.%s=p.%s
- AND
- e.%s=%s',
- $this->table,$this->table,
- $this->_getWhereAddOn(' AND ', 'p'),
- $this->_getColName('left'),
- $this->_getColName('right'),
- $this->_getColName('parentId'),
- $this->_getColName('parentId'),
- $this->_getColName('id'),
- $id);
- if (DB::isError($res = $this->dbh->getRow($query))) {
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- return !$res ? false : $this->_prepareResult($res);
- }
-
- // }}}
- // {{{ isChildOf()
-
- /**
- * returns if $childId is a child of $id
- *
- * @abstract
- * @version 2002/04/29
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param int id of the element
- * @param int id of the element to check if it is a child
- * @return boolean true if it is a child
- */
- function isChildOf($id, $childId)
- {
- // check simply if the left and right of the child are within the
- // left and right of the parent, if so it definitly is a child :-)
- $parent = $this->getElement($id);
- $child = $this->getElement($childId);
-
- if ($parent['left'] < $child['left']
- && $parent['right'] > $child['right']) {
- return true;
- }
- return false;
- }
-
- // }}}
- // {{{ getDepth()
-
- /**
- * return the maximum depth of the tree
- *
- * @version 2003/02/25
- * @access public
- * @author "Denis Joloudov" <dan@aitart.ru>, Wolfram Kriesing <wolfram@kriesing.de>
- * @return integer the depth of the tree
- */
- function getDepth()
- {
- // FIXXXME TODO!!!
- $query = sprintf('SELECT COUNT(*) FROM %s p, %s e '.
- 'WHERE %s (e.%s BETWEEN p.%s AND p.%s) AND '.
- '(e.%s BETWEEN p.%s AND p.%s)',
- $this-> table,$this->table,
- // first line in where
- $this->_getWhereAddOn(' AND ','p'),
- $this->_getColName('left'),$this->_getColName('left'),
- $this->_getColName('right'),
- // second where line
- $this->_getColName('right'),$this->_getColName('left'),
- $this->_getColName('right')
- );
- if (DB::isError($res = $this->dbh->getOne($query))) {
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- if (!$res) {
- return false;
- }
- return $this->_prepareResult($res);
- }
-
- // }}}
- // {{{ hasChildren()
-
- /**
- * Tells if the node with the given ID has children.
- *
- * @version 2003/03/04
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param integer the ID of a node
- * @return boolean if the node with the given id has children
- */
- function hasChildren($id)
- {
- $element = $this->getElement($id);
- // if the diff between left and right>1 then there are children
- return ($element['right'] - $element['left']) > 1;
- }
-
- // }}}
- // {{{ getIdByPath()
-
- /**
- * return the id of the element which is referenced by $path
- * this is useful for xml-structures, like: getIdByPath('/root/sub1/sub2')
- * this requires the structure to use each name uniquely
- * if this is not given it will return the first proper path found
- * i.e. there should only be one path /x/y/z
- * experimental: the name can be non unique if same names are in different levels
- *
- * @version 2003/05/11
- * @access public
- * @author Pierre-Alain Joye <paj@pearfr.org>
- * @param string $path the path to search for
- * @param integer $startId the id where to start the search
- * @param string $nodeName the name of the key that contains
- * the node name
- * @param string $seperator the path seperator
- * @return integer the id of the searched element
- */
- function getIdByPath($path, $startId = 0, $nodeName = 'name', $separator = '/')
- // should this method be called getElementIdByPath ????
- // Yes, with an optional private paramater to get the whole node
- // in preference to only the id?
- {
- if ($separator == '') {
- return $this->_throwError(
- 'getIdByPath: Empty separator not allowed', __LINE__);
- }
- if ($path == $separator) {
- $root = $this->getRoot();
- if (Tree::isError($root)) {
- return $root;
- }
- return $root['id'];
- }
- if (!($colname=$this->_getColName($nodeName))) {
- return $this->_throwError(
- 'getIdByPath: Invalid node name', __LINE__);
- }
- if ($startId != 0) {
- // If the start node has no child, returns false
- // hasChildren calls getElement. Not very good right
- // now. See the TODO
- $startElem = $this->getElement($startId);
- if (!is_array($startElem) || Tree::isError($startElem)) {
- return $startElem;
- }
- // No child? return
- if (!is_array($startElem)) {
- return null;
- }
- $rangeStart = $startElem['left'];
- $rangeEnd = $startElem['right'];
- // Not clean, we should call hasChildren, but I do not
- // want to call getELement again :). See TODO
- $startHasChild = ($rangeEnd-$rangeStart)>1?true:false;
- $cwd = '/'.$this->getPathAsString($startId);
- } else {
- $cwd = '/';
- $startHasChild = false;
- }
- $t = $this->_preparePath($path, $cwd, $separator);
- if (Tree::isError($t)) {
- return $t;
- }
- list($elems, $sublevels) = $t;
- $cntElems = sizeof($elems);
- $where = '';
-
- $query = 'SELECT '
- .$this->_getColName('id')
- .' FROM '
- .$this->table
- . ' WHERE '
- .$colname;
- if ($cntElems == 1) {
- $query .= "='".$elems[0]."'";
- } else {
- $query .= "='".$elems[$cntElems-1]."'";
- }
- if ($startHasChild) {
- $where .= ' AND ('.
- $this->_getColName('left').'>'.$rangeStart.
- ' AND '.
- $this->_getColName('right').'<'.$rangeEnd.')';
- }
- $res = $this->dbh->getOne($query);
- if (DB::isError($res)) {
- return $this->_throwError($res->getMessage(),
- __LINE__);
- }
- return ($res ? (int)$res : false);
- }
-
- // }}}
-
- //
- // PRIVATE METHODS
- //
-
- // {{{ _getWhereAddOn()
- /**
- *
- *
- * @access private
- * @version 2002/04/20
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param string the current where clause
- * @return string the where clause we want to add to a query
- */
- function _getWhereAddOn($addAfter = ' AND ', $tableName = '')
- {
- if ($where = $this->getOption('whereAddOn')) {
- return ' '.($tableName ? $tableName.'.' : '')." $where$addAfter ";
- }
- return '';
- }
-
- // }}}
- // {{{ getFirstRoot()
-
- // for compatibility to Memory methods
- function getFirstRoot()
- {
- return $this->getRoot();
- }
-
- // }}}
- // {{{ getNode()
-
- /**
- * gets the tree under the given element in one array, sorted
- * so you can go through the elements from begin to end and list them
- * as they are in the tree, where every child (until the deepest) is retreived
- *
- * @see &_getNode()
- * @access public
- * @version 2001/12/17
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param integer $startId the id where to start walking
- * @param integer $depth this number says how deep into
- * the structure the elements shall
- * be retreived
- * @return array sorted as listed in the tree
- */
- function &getNode($startId = 0, $depth = 0)
- {
-//FIXXXME use getChildren()
- if ($startId) {
- $startNode = $this->getElement($startId);
- if (Tree::isError($startNode)) {
- return $startNode;
- }
-
- } else {
- }
- }
-}
-
-/*
- * Local Variables:
- * mode: php
- * tab-width: 4
- * c-basic-offset: 4
- * End:
- */
\ No newline at end of file
Index: Tree/Dynamic/SQLnested.php
===================================================================
--- Tree/Dynamic/SQLnested.php (.../branches/Tree_0_3_0) (revision 0)
+++ Tree/Dynamic/SQLnested.php (.../trunk) (revision 321102)
@@ -0,0 +1,1317 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+// +----------------------------------------------------------------------+
+// | PHP Version 4 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1997-2005 The PHP Group |
+// +----------------------------------------------------------------------+
+// | This source file is subject to version 3.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/3_0.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: |
+// +----------------------------------------------------------------------+
+//
+// $Id$
+
+require_once 'Tree/Tree.php';
+
+/**
+* This class implements methods to work on a tree saved using the nested
+* tree model.
+* explaination: http://research.calacademy.org/taf/proceedings/ballew/index.htm
+*
+* @access public
+* @package Tree
+*/
+class Tree_Dynamic_SQLnested extends Tree
+{
+ // {{{ __construct()
+
+ // the defined methods here are proposals for the implementation,
+ // they are named the same, as the methods in the "Memory" branch.
+ // If possible it would be cool to keep the same naming. And
+ // if the same parameters would be possible too then it would be
+ // even better, so one could easily change from any kind
+ // of tree-implementation to another, without changing the source
+ // code, only the setupXXX would need to be changed
+ /**
+ *
+ *
+ * @access public
+ * @version 2002/03/02
+ * @param string the DSN for the DB connection
+ * @return void
+ */
+ function __construct($config)
+ {
+ $this->Tree_Dynamic_SQLnested($config);
+ }
+
+ // }}}
+ // {{{ Tree_Dynamic_DBnested()
+
+ /**
+ *
+ *
+ * @access public
+ * @version 2002/03/02
+ * @author Wolfram Kriesing <wolfram@kriesing.de>
+ * @param string the DSN for the DB connection
+ * @return void
+ */
+ function Tree_Dynamic_SQLnested($config)
+ {
+ $this->conf = Tree::arrayMergeClobber($this->conf, $config['options']);
+ $this->init($config);
+ }
+
+ // }}}
+ // {{{ add()
+
+ /**
+ * add a new element to the tree
+ * there are three ways to use this method
+ * Method 1:
+ * Give only the $parent_id and the $newValues will be inserted
+ * as the first child of this parent
+ * <code>
+ * // insert a new element under the parent with the ID=7
+ * $tree->add(array('name'=>'new element name'), 7);
+ * </code>
+ *
+ * Method 2:
+ * Give the $prevId ($parent_id will be dismissed) and the new element
+ * will be inserted in the tree after the element with the ID=$prevId
+ * the parent_id is not necessary because the prevId defines exactly where
+ * the new element has to be place in the tree, and the parent is
+ * the same as for the element with the ID=$prevId
+ * <code>
+ * // insert a new element after the element with the ID=5
+ * $tree->add(array('name'=>'new'), 0, 5);
+ * </code>
+ *
+ * Method 3:
+ * neither $parent_id nor prevId is given, then the root element will be
+ * inserted. This requires that programmer is responsible to confirm this.
+ * This method does not yet check if there is already a root element saved!
+ *
+ * @access public
+ * @param array $newValues this array contains the values that shall
+ * be inserted in the db-table
+ * @param integer $parent_id the id of the element which shall be
+ * the parent of the new element
+ * @param integer $prevId the id of the element which shall preceed
+ * the one to be inserted use either
+ * 'parent_id' or 'prevId'.
+ * @return integer the ID of the element that had been inserted
+ */
+ function add($newValues, $parent_id = 0, $prevId = 0)
+ {
+ $left = $this->_getColName('left');
+ $right = $this->_getColName('right');
+ $prevVisited = 0;
+
+ // check the DB-table if the columns which are given as keys
+ // in the array $newValues do really exist, if not remove them
+ // from the array
+ // FIXXME do the above described
+ // if no parent and no prevId is given the root shall be added
+ if ($parent_id || $prevId) {
+ if ($prevId) {
+ $element = $this->getElement($prevId);
+ if (Tree::isError($element)) {
+ return $element;
+ }
+ // we also need the parent id of the element to write it in the db
+ $parent_id = $element['parent_id'];
+ } else {
+ $element = $this->getElement($parent_id);
+ }
+ $newValues['parent_id'] = $parent_id;
+
+ if (Tree::isError($element)) {
+ return $element;
+ }
+
+ // get the "visited"-value where to add the new element behind
+ // if $prevId is given, we need to use the right-value
+ // if only the $parent_id is given we need to use the left-value
+ // look at it graphically, that made me understand it :-)
+ // See:
+ // http://research.calacademy.org/taf/proceedings/ballew/sld034.htm
+ $prevVisited = $prevId ? $element['right'] : $element['left'];
+
+ // FIXXME start transaction here
+ if (Tree::isError($err = $this->_add($prevVisited, 1))) {
+ // FIXXME rollback
+ //$this->_storage->rollback();
+ return $err;
+ }
+ }
+
+ // inserting _one_ new element in the tree
+ $newData = array();
+ // quote the values, as needed for the insert
+ foreach ($newValues as $key => $value) {
+ $type = $this->conf['fields'][$key]['type'];
+ $newData[$this->_getColName($key)] = $this->_storage->quote($value, $type);
+ }
+
+ // set the proper right and left values
+ $newData[$left] = $prevVisited + 1;
+ $newData[$right] = $prevVisited + 2;
+
+ // use sequences to create a new id in the db-table
+ $nextId = $this->_storage->nextId($this->conf['table']);
+ $query = sprintf('INSERT INTO %s (%s, %s) VALUES (%s, %s)',
+ $this->conf['table'],
+ $this->_getColName('id'),
+ implode(',', array_keys($newData)) ,
+ $this->_storage->quote($nextId, 'integer'),
+ implode(',', $newData)
+ );
+ $res = $this->_storage->query($query);
+ if (PEAR::isError($res)) {
+ // rollback
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $res->getMessage());
+ }
+ // commit here
+
+ return $nextId;
+ }
+
+ // }}}
+ // {{{ _add()
+
+ /**
+ * this method only updates the left/right values of all the
+ * elements that are affected by the insertion
+ * be sure to set the parent_id of the element(s) you insert
+ *
+ * @param int this parameter is not the ID!!!
+ * it is the previous visit number, that means
+ * if you are inserting a child, you need to use the left-value
+ * of the parent
+ * if you are inserting a "next" element, on the same level
+ * you need to give the right value !!
+ * @param int the number of elements you plan to insert
+ * @return mixed either true on success or a Tree_Error on failure
+ */
+ function _add($prevVisited, $numberOfElements = 1)
+ {
+ $left = $this->_getColName('left');
+ $right = $this->_getColName('right');
+
+ // update the elements which will be affected by the new insert
+ $query = sprintf('UPDATE %s SET %s = %s + %s WHERE%s %s > %s',
+ $this->conf['table'],
+ $left,
+ $left,
+ $numberOfElements * 2,
+ $this->_getWhereAddOn(),
+ $left,
+ $prevVisited);
+ if (PEAR::isError($res = $this->_storage->query($query))) {
+ // FIXXME rollback
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $res->getMessage());
+ }
+
+ $query = sprintf('UPDATE %s SET %s = %s + %s WHERE%s %s > %s',
+ $this->conf['table'],
+ $right, $right,
+ $numberOfElements * 2,
+ $this->_getWhereAddOn(),
+ $right,
+ $prevVisited);
+ $res = $this->_storage->query($query);
+ if (PEAR::isError($res)) {
+ // FIXXME rollback
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $res->getMessage());
+ }
+ return true;
+ }
+
+ // }}}
+ // {{{ remove()
+
+ /**
+ * remove a tree element
+ * this automatically remove all children and their children
+ * if a node shall be removed that has children
+ *
+ * @access public
+ * @param integer $id the id of the element to be removed
+ * @return boolean returns either true or throws an error
+ */
+ function remove($id)
+ {
+ $element = $this->getElement($id);
+ if (Tree::isError($element)) {
+ return $element;
+ }
+
+ // FIXXME start transaction
+ //$this->_storage->autoCommit(false);
+ $query = sprintf('DELETE FROM %s WHERE%s %s BETWEEN %s AND %s',
+ $this->conf['table'],
+ $this->_getWhereAddOn(),
+ $this->_getColName('left'),
+ $element['left'], $element['right']);
+ $res = $this->_storage->query($query);
+ if (PEAR::isError($res)) {
+ // FIXXME rollback
+ //$this->_storage->rollback();
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $res->getMessage());
+ }
+
+ if (Tree::isError($err = $this->_remove($element))) {
+ // FIXXME rollback
+ //$this->_storage->rollback();
+ return $err;
+ }
+ return true;
+ }
+
+ // }}}
+ // {{{ _remove()
+
+ /**
+ * removes a tree element, but only updates the left/right values
+ * to make it seem as if the given element would not exist anymore
+ * it doesnt remove the row(s) in the db itself!
+ *
+ * @see getElement()
+ * @access private
+ * @param array the entire element returned by "getElement"
+ * @return boolean returns either true or throws an error
+ */
+ function _remove($element)
+ {
+ $delta = $element['right'] - $element['left'] + 1;
+ $left = $this->_getColName('left');
+ $right = $this->_getColName('right');
+
+ // update the elements which will be affected by the remove
+ $query = sprintf("UPDATE
+ %s
+ SET
+ %s = %s - $delta,
+ %s = %s - $delta
+ WHERE%s %s > %s",
+ $this->conf['table'],
+ $left, $left,
+ $right, $right,
+ $this->_getWhereAddOn(),
+ $left, $element['left']);
+ $res = $this->_storage->query($query);
+ if (PEAR::isError($res)) {
+ // the rollback shall be done by the method calling this one
+ // since it is only private we can do that
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $res->getMessage());
+ }
+
+ $query = sprintf("UPDATE
+ %s
+ SET %s = %s - $delta
+ WHERE
+ %s %s < %s
+ AND
+ %s > %s",
+ $this->conf['table'],
+ $right, $right,
+ $this->_getWhereAddOn(),
+ $left, $element['left'],
+ $right, $element['right']);
+ $res = $this->_storage->query($query);
+ if (PEAR::isError($res)) {
+ // the rollback shall be done by the method calling this one
+ // since it is only private
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $res->getMessage());
+ }
+ // FIXXME commit:
+ // should that not also be done in the method calling this one?
+ // like when an error occurs?
+ //$this->_storage->commit();
+ return true;
+ }
+
+ // }}}
+ // {{{ move()
+
+ /**
+ * move an entry under a given parent or behind a given entry.
+ * If a newPrevId is given the newparent_id is dismissed!
+ * call it either like this:
+ * $tree->move(x, y)
+ * to move the element (or entire tree) with the id x
+ * under the element with the id y
+ * or
+ * $tree->move(x, 0, y); // ommit the second parameter by setting
+ * it to 0
+ * to move the element (or entire tree) with the id x
+ * behind the element with the id y
+ * or
+ * $tree->move(array(x1,x2,x3), ...
+ * the first parameter can also be an array of elements that shall
+ * be moved. the second and third para can be as described above.
+ *
+ * If you are using the Memory_DBnested then this method would be invain,
+ * since Memory.php already does the looping through multiple elements.
+ * But if Dynamic_DBnested is used we need to do the looping here
+ *
+ * @version 2002/06/08
+ * @access public
+ * @param integer the id(s) of the element(s) that shall be moved
+ * @param integer the id of the element which will be the new parent
+ * @param integer if prevId is given the element with the id idToMove
+ * shall be moved _behind_ the element with id=prevId
+ * if it is 0 it will be put at the beginning
+ * @return mixed true for success, Tree_Error on failure
+ */
+ function move($idsToMove, $newparent_id, $newPrevId = 0)
+ {
+ settype($idsToMove, 'array');
+ $errors = array();
+ foreach ($idsToMove as $idToMove) {
+ $ret = $this->_move($idToMove, $newparent_id, $newPrevId);
+ if (Tree::isError($ret)) {
+ $errors[] = $ret;
+ }
+ }
+ // FIXXME the error in a nicer way, or even better
+ // let the throwError method do it!!!
+ if (count($errors)) {
+ return Tree::raiseError(TREE_ERROR_UNKOWN_ERROR, null, null, serialize($errors));
+ }
+ return true;
+ }
+
+ // }}}
+ // {{{ _move()
+
+ /**
+ * this method moves one tree element
+ *
+ * @see move()
+ * @version 2002/04/29
+ * @access public
+ * @param integer the id of the element that shall be moved
+ * @param integer the id of the element which will be the new parent
+ * @param integer if prevId is given the element with the id idToMove
+ * shall be moved _behind_ the element with id=prevId
+ * if it is 0 it will be put at the beginning
+ * @return mixed true for success, Tree_Error on failure
+ */
+ function _move($idToMove, $newparent_id, $newPrevId = 0)
+ {
+ // do some integrity checks first
+ if ($newPrevId) {
+ // dont let people move an element behind itself, tell it
+ // succeeded, since it already is there :-)
+ if ($newPrevId == $idToMove) {
+ return true;
+ }
+ if (Tree::isError($newPrevious = $this->getElement($newPrevId))) {
+ return $newPrevious;
+ }
+ $newparent_id = $newPrevious['parent_id'];
+ } else {
+ if ($newparent_id == 0) {
+ return Tree::raiseError(TREE_ERROR_UNKOWN_ERROR, null, null, 'no parent id given');
+ }
+ // if the element shall be moved under one of its children
+ // return false
+ if ($this->isChildOf($idToMove, $newparent_id)) {
+ return Tree::raiseError(TREE_ERROR_UNKOWN_ERROR, null, null,
+ 'can not move an element under one of its children');
+ }
+ // dont do anything to let an element be moved under itself
+ // which is bullshit
+ if ($newparent_id == $idToMove) {
+ return true;
+ }
+ // try to retreive the data of the parent element
+ if (Tree::isError($newParent = $this->getElement($newparent_id))) {
+ return $newParent;
+ }
+ }
+ // get the data of the element itself
+ if (Tree::isError($element = $this->getElement($idToMove))) {
+ return $element;
+ }
+
+ $numberOfElements = ($element['right'] - $element['left'] + 1) / 2;
+ $prevVisited = $newPrevId ? $newPrevious['right'] : $newParent['left'];
+
+ // FIXXME start transaction
+
+ // add the left/right values in the new parent, to have the space
+ // to move the new values in
+ $err = $this->_add($prevVisited, $numberOfElements);
+ if (Tree::isError($err)) {
+ // FIXXME rollback
+ //$this->_storage->rollback();
+ return $err;
+ }
+
+ // update the parent_id of the element with $idToMove
+ $err = $this->update($idToMove, array('parent_id' => $newparent_id));
+ if (Tree::isError($err)) {
+ // FIXXME rollback
+ //$this->_storage->rollback();
+ return $err;
+ }
+
+ // update the lefts and rights of those elements that shall be moved
+
+ // first get the offset we need to add to the left/right values
+ // if $newPrevId is given we need to get the right value,
+ // otherwise the left since the left/right has changed
+ // because we already updated it up there. We need to get them again.
+ // We have to do that anyway, to have the proper new left/right values
+ if ($newPrevId) {
+ if (Tree::isError($temp = $this->getElement($newPrevId))) {
+ // FIXXME rollback
+ //$this->_storage->rollback();
+ return $temp;
+ }
+ $calcWith = $temp['right'];
+ } else {
+ if (Tree::isError($temp = $this->getElement($newparent_id))) {
+ // FIXXME rollback
+ //$this->_storage->rollback();
+ return $temp;
+ }
+ $calcWith = $temp['left'];
+ }
+
+ // get the element that shall be moved again, since the left and
+ // right might have changed by the add-call
+ if (Tree::isError($element = $this->getElement($idToMove))) {
+ return $element;
+ }
+ // calc the offset that the element to move has
+ // to the spot where it should go
+ // correct the offset by one, since it needs to go inbetween!
+ $offset = $calcWith - $element['left'] + 1;
+
+ $left = $this->_getColName('left');
+ $right = $this->_getColName('right');
+ $query = sprintf("UPDATE
+ %s
+ SET
+ %s = %s + $offset,
+ %s = %s + $offset
+ WHERE
+ %s %s > %s
+ AND
+ %s < %s",
+ $this->conf['table'],
+ $right, $right,
+ $left, $left,
+ $this->_getWhereAddOn(),
+ $left, $element['left'] - 1,
+ $right, $element['right'] + 1);
+ if (PEAR::isError($res = $this->_storage->query($query))) {
+ // FIXXME rollback
+ //$this->_storage->rollback();
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $res->getMessage());
+ }
+
+ // remove the part of the tree where the element(s) was/were before
+ if (Tree::isError($err = $this->_remove($element))) {
+ // FIXXME rollback
+ //$this->_storage->rollback();
+ return $err;
+ }
+ // FIXXME commit all changes
+ //$this->_storage->commit();
+
+ return true;
+ }
+
+ // }}}
+ // {{{ update()
+
+ /**
+ * update the tree element given by $id with the values in $newValues
+ *
+ * @access public
+ * @param int the id of the element to update
+ * @param array the new values, the index is the col name
+ * @return mixed either true or an Tree_Error
+ */
+ function update($id, $newValues)
+ {
+ // just to be sure nothing gets screwed up :-)
+ unset($newValues[$this->_getColName('left')]);
+ unset($newValues[$this->_getColName('right')]);
+ unset($newValues[$this->_getColName('parent_id')]);
+
+ // updating _one_ element in the tree
+ $values = array();
+ foreach ($newValues as $key => $value) {
+ $type = $this->conf['fields'][$key]['type'];
+ $values[] = $this->_getColName($key) . ' = ' . $this->_storage->quote($value, $type);
+ }
+ $query = sprintf('UPDATE %s SET %s WHERE%s %s = %s',
+ $this->conf['table'],
+ implode(',', $values),
+ $this->_getWhereAddOn(),
+ $this->_getColName('id'),
+ $id);
+ $res = $this->_storage->query($query);
+ if (PEAR::isError($res)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $res->getMessage());
+ }
+
+ return true;
+ }
+
+ // }}}
+ // {{{ update()
+
+ /**
+ * copy a subtree/node/... under a new parent or/and behind a given element
+ *
+ *
+ * @access public
+ * @param integer the ID of the node that shall be copied
+ * @param integer the new parent ID
+ * @param integer the new previous ID, if given parent ID will be omitted
+ * @return boolean true on success
+ */
+ function copy($id, $parent_id = 0, $prevId = 0)
+ {
+ return Tree::raiseError(TREE_ERROR_NOT_IMPLEMENTED, null, null,
+ 'copy-method is not implemented yet!');
+ // get element tree
+ // $this->addTree
+ }
+
+ // }}}
+ // {{{ getRoot()
+
+ /**
+ * get the root
+ *
+ * @access public
+ * @version 2002/03/02
+ * @author Wolfram Kriesing <wolfram@kriesing.de>
+ * @return mixed either the data of the root element or an Tree_Error
+ */
+ function getRoot()
+ {
+ $query = sprintf('SELECT * FROM %s WHERE%s %s = 1',
+ $this->conf['table'],
+ $this->_getWhereAddOn(),
+ $this->_getColName('left'));
+ $res = $this->_storage->queryRow($query, array());
+ if (PEAR::isError($res)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $res->getMessage());
+ }
+
+ return !$res ? false : $this->_prepareResult($res);
+ }
+
+ // }}}
+ // {{{ getElement()
+
+ /**
+ *
+ *
+ * @access public
+ * @version 2002/03/02
+ * @author Wolfram Kriesing <wolfram@kriesing.de>
+ * @param integer the ID of the element to return
+ *
+ * @return mixed either the data of the requested element
+ * or an Tree_Error
+ */
+ function getElement($id)
+ {
+ $query = sprintf('SELECT * FROM %s WHERE %s %s = %s',
+ $this->conf['table'],
+ $this->_getWhereAddOn(),
+ $this->_getColName('id'),
+ $id);
+ $res = $this->_storage->queryRow($query, array());
+ if (PEAR::isError($res)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $res->getMessage());
+ }
+
+ if (!$res) {
+ return Tree::raiseError(TREE_ERROR_UNKOWN_ERROR, null, null, "Element with id $id does not exist!");
+ }
+
+ return $this->_prepareResult($res);
+ }
+
+ // }}}
+ // {{{ getPath()
+
+ /**
+ * gets the path from the element with the given id down
+ * to the root. The returned array is sorted to start at root
+ * for simply walking through and retreiving the path
+ *
+ * @access public
+ * @param integer the ID of the element for which the path shall be returned
+ * @return mixed either the data of the requested elements
+ * or an Tree_Error
+ */
+ function getPath($id)
+ {
+ $query = $this->_getPathQuery($id);
+ if (PEAR::isError($query)) {
+ /// FIXME return real tree error
+ return false;
+ }
+
+ $res = $this->_storage->queryAll($query, array(), false, false);
+ if (PEAR::isError($res)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $res->getMessage());
+ }
+
+ return $this->_prepareResults($res);
+ }
+
+ // }}}
+ // {{{ _getPathQuery()
+
+ function _getPathQuery($id)
+ {
+ // subqueries would be cool :-)
+ $curElement = $this->getElement($id);
+ if (PEAR::isError($curElement)) {
+ /// FIXME return real tree error
+ return false;
+ }
+
+ $left = $this->_getColName('left');
+ $query = sprintf('SELECT * FROM %s '.
+ 'WHERE %s %s <= %s AND %s >= %s '.
+ 'ORDER BY %s',
+ // set the FROM %s
+ $this->conf['table'],
+ // set the additional where add on
+ $this->_getWhereAddOn(),
+ // render 'left<=curLeft'
+ $left, $curElement['left'],
+ // render right>=curRight'
+ $this->_getColName('right'), $curElement['right'],
+ // set the order column
+ $left);
+ return $query;
+ }
+
+ // }}}
+ // {{{ getLevel()
+
+ function getLevel($id)
+ {
+ $query = $this->_getPathQuery($id);
+ // i know this is not really beautiful ...
+ $id = $this->_getColName('id');
+ $replace = "SELECT COUNT($id) ";
+ $query = preg_replace('/^select \* /i', $replace, $query);
+ $res = $this->_storage->queryOne($query, 'integer');
+ if (PEAR::isError($res)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $res->getMessage());
+ }
+
+ return $res - 1;
+ }
+
+ // }}}
+ // {{{ getLeft()
+
+ /**
+ * gets the element to the left, the left visit
+ *
+ * @access public
+ * @version 2002/03/07
+ * @author Wolfram Kriesing <wolfram@kriesing.de>
+ * @param integer the ID of the element
+ * @return mixed either the data of the requested element
+ * or an Tree_Error
+ */
+ function getLeft($id)
+ {
+ $element = $this->getElement($id);
+ if (Tree::isError($element)) {
+ return $element;
+ }
+
+ $query = sprintf('SELECT * FROM %s WHERE%s (%s = %s OR %s = %s)',
+ $this->conf['table'],
+ $this->_getWhereAddOn(),
+ $this->_getColName('right'), $element['left'] - 1,
+ $this->_getColName('left'), $element['left'] - 1);
+ $res = $this->_storage->queryRow($query, array());
+ if (PEAR::isError($res)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $res->getMessage());
+ }
+
+ return $this->_prepareResult($res);
+ }
+
+ // }}}
+ // {{{ getRight()
+
+ /**
+ * gets the element to the right, the right visit
+ *
+ * @access public
+ * @version 2002/03/07
+ * @author Wolfram Kriesing <wolfram@kriesing.de>
+ * @param integer the ID of the element
+ * @return mixed either the data of the requested element
+ * or an Tree_Error
+ */
+ function getRight($id)
+ {
+ $element = $this->getElement($id);
+ if (Tree::isError($element)) {
+ return $element;
+ }
+
+ $query = sprintf('SELECT * FROM %s WHERE%s (%s = %s OR %s = %s)',
+ $this->conf['table'],
+ $this->_getWhereAddOn(),
+ $this->_getColName('left'), $element['right'] + 1,
+ $this->_getColName('right'), $element['right'] + 1);
+ $res = $this->_storage->queryRow($query, array());
+ if (PEAR::isError($res)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $res->getMessage());
+ }
+
+ return $this->_prepareResult($res);
+ }
+
+ // }}}
+ // {{{ getParent()
+
+ /**
+ * get the parent of the element with the given id
+ *
+ * @access public
+ * @version 2002/04/15
+ * @author Wolfram Kriesing <wolfram@kriesing.de>
+ * @param integer the ID of the element
+ * @return mixed the array with the data of the parent element
+ * or false, if there is no parent, if the element is
+ * the root or an Tree_Error
+ */
+ function getParent($id)
+ {
+ $idName = $this->_getColName('id');
+ $query = sprintf('SELECT
+ p.*
+ FROM
+ %s p,%s e
+ WHERE
+ %s e.%s = p.%s
+ AND
+ e.%s = %s',
+ $this->conf['table'], $this->conf['table'],
+ $this->_getWhereAddOn(' AND ', 'p'),
+ $this->_getColName('parent_id'),
+ $idName,
+ $idName,
+ $id);
+ $res = $this->_storage->queryRow($query, array());
+ if (PEAR::isError($res)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $res->getMessage());
+ }
+
+ return $this->_prepareResult($res);
+ }
+
+ // }}}
+ // {{{ getChild()
+
+ /**
+ *
+ *
+ * @access public
+ * @version 2002/03/02
+ * @param integer the ID of the element for which the children
+ * shall be returned
+ * @return mixed either the data of the requested element or an Tree_Error
+ */
+ function _getChild($id)
+ {
+ // subqueries would be cool :-)
+ $curElement = $this->getElement($id);
+ if (Tree::isError($curElement)) {
+ return $curElement;
+ }
+
+ $query = sprintf('SELECT * FROM %s WHERE%s %s = %s',
+ $this->conf['table'],
+ $this->_getWhereAddOn(),
+ $this->_getColName('left'),
+ $curElement['left'] + 1);
+ $res = $this->_storage->queryRow($query, array());
+ if (PEAR::isError($res)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $res->getMessage());
+ }
+ return $this->_prepareResult($res);
+ }
+
+ // }}}
+ // {{{ getChildren()
+
+ /**
+ * get the children of the given element or if the parameter is an array.
+ * It gets the children of all the elements given by their ids
+ * in the array.
+ *
+ * @access public
+ * @version 2002/04/15
+ * @author Wolfram Kriesing <wolfram@kriesing.de>
+ * @param mixed (1) int the id of one element
+ * (2) array an array of ids for which
+ * the children will be returned
+ * @param boolean if only the first child should be returned (only used when one id is passed)
+ * @param integer the children of how many levels shall be returned
+ * @return mixed the array with the data of all children
+ * or false, if there are none
+ */
+ function getChildren($ids, $oneChild = false, $levels = 1)
+ {
+ if ($oneChild) {
+ $res = $this->_getChild($ids);
+ return $res;
+ }
+
+ $id = $this->_getColName('id');
+ $parent = $this->_getColName('parent_id');
+ $left = $this->_getColName('left');
+ $where = $this->_getWhereAddOn(' AND ', 'c');
+ $orderBy = $this->getOption('order') ? $this->getOption('order') : $left;
+
+ $res = array();
+ for ($i = 1; $i < $levels + 1; $i++) {
+ // if $ids is an array implode the values
+ $getIds = is_array($ids) ? implode(',', $ids) : $ids;
+
+ $query = sprintf('SELECT
+ c.*
+ FROM
+ %s c,%s e
+ WHERE
+ %s e.%s = c.%s
+ AND
+ e.%s IN (%s) '.
+ 'ORDER BY
+ c.%s',
+ $this->conf['table'], $this->conf['table'],
+ $where,
+ $id,
+ $parent,
+ $id,
+ $getIds,
+ // order by left, so we have it in the order
+ // as it is in the tree if no 'order'-option
+ // is given
+ $orderBy
+ );
+ $_res = $this->_storage->queryAll($query, array(), false, false);
+ if (PEAR::isError($_res)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $_res->getMessage());
+ }
+
+ // Column names are now unmapped
+ $_res = $this->_prepareResults($_res);
+
+ if ($levels > 1) {
+ $ids = array();
+ }
+
+ // we use the id as the index, to make the use easier esp.
+ // for multiple return-values
+ $tempRes = array();
+ foreach ($_res as $aRes) {
+ ///FIXME This part might be replace'able with key'ed array return
+ $tempRes[$aRes['id']] = $aRes;
+ // If there are more levels requested then get the id for the next level
+ if ($levels > 1) {
+ $ids[] = $aRes[$id];
+ }
+ }
+
+ $res = array_merge($res, $tempRes);
+
+ // quit the for-loop if there are no children in the current level
+ if (!count($ids)) {
+ break;
+ }
+ }
+
+ return $res;
+ }
+
+ // }}}
+ // {{{ nextSibling()
+
+ /**
+ * get the next element on the same level
+ * if there is none return false
+ *
+ * @access public
+ * @version 2002/04/15
+ * @author Wolfram Kriesing <wolfram@kriesing.de>
+ * @param integer the ID of the element
+ * @return mixed the array with the data of the next element
+ * or false, if there is no next
+ * or Tree_Error
+ */
+ function nextSibling($id)
+ {
+ $parent = $this->_getColName('parent_id');
+ $query = sprintf('SELECT
+ n.*
+ FROM
+ %s n, %s e
+ WHERE
+ %s e.%s = n.%s - 1
+ AND
+ e.%s = n.%s
+ AND
+ e.%s = %s',
+ $this->conf['table'], $this->conf['table'],
+ $this->_getWhereAddOn(' AND ', 'n'),
+ $this->_getColName('right'),
+ $this->_getColName('left'),
+ $parent,
+ $parent,
+ $this->_getColName('id'),
+ $id);
+ $res = $this->_storage->queryRow($query, array());
+ if (PEAR::isError($res)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $res->getMessage());
+ }
+
+ return !$res ? false : $this->_prepareResult($res);
+ }
+
+ // }}}
+ // {{{ previousSibling()
+
+ /**
+ * get the previous element on the same level
+ * if there is none return false
+ *
+ * @access public
+ * @version 2002/04/15
+ * @author Wolfram Kriesing <wolfram@kriesing.de>
+ * @param integer the ID of the element
+ * @return mixed the array with the data of the previous element
+ * or false, if there is no previous
+ * or a Tree_Error
+ */
+ function previousSibling($id)
+ {
+ $parent = $this->_getColName('parent_id');
+ $query = sprintf('SELECT
+ p.*
+ FROM
+ %s p, %s e
+ WHERE
+ %s e.%s = p.%s + 1
+ AND
+ e.%s = p.%s
+ AND
+ e.%s = %s',
+ $this->conf['table'], $this->conf['table'],
+ $this->_getWhereAddOn(' AND ', 'p'),
+ $this->_getColName('left'),
+ $this->_getColName('right'),
+ $parent,
+ $parent,
+ $this->_getColName('id'),
+ $id);
+ $res = $this->_storage->queryRow($query, array());
+ if (PEAR::isError($res)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $res->getMessage());
+ }
+
+ return !$res ? false : $this->_prepareResult($res);
+ }
+
+ // }}}
+ // {{{ isChildOf()
+
+ /**
+ * returns if $childId is a child of $id
+ *
+ * @abstract
+ * @version 2002/04/29
+ * @access public
+ * @author Wolfram Kriesing <wolfram@kriesing.de>
+ * @param int id of the element
+ * @param int id of the element to check if it is a child
+ * @return boolean true if it is a child
+ */
+ function isChildOf($id, $childId)
+ {
+ // check simply if the left and right of the child are within the
+ // left and right of the parent, if so it definitly is a child :-)
+ $parent = $this->getElement($id);
+ if (PEAR::isError($parent)) {
+ /// FIXME return real tree error
+ return false;
+ }
+
+ $child = $this->getElement($childId);
+ if (PEAR::isError($child)) {
+ /// FIXME return real tree error
+ return false;
+ }
+
+ if ($parent['left'] < $child['left']
+ && $parent['right'] > $child['right'])
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ // }}}
+ // {{{ getDepth()
+
+ /**
+ * return the maximum depth of the tree
+ *
+ * @version 2003/02/25
+ * @access public
+ * @author "Denis Joloudov" <dan@aitart.ru>, Wolfram Kriesing <wolfram@kriesing.de>
+ * @return integer the depth of the tree
+ */
+ function getDepth()
+ {
+ $left = $this->_getColName('left');
+ $right = $this->_getColName('right');
+ // FIXXXME TODO!!!
+ $query = sprintf('SELECT COUNT(*) FROM %s p, %s e '.
+ 'WHERE %s (e.%s BETWEEN p.%s AND p.%s) AND '.
+ '(e.%s BETWEEN p.%s AND p.%s)',
+ $this->conf['table'], $this->conf['table'],
+ // first line in where
+ $this->_getWhereAddOn(' AND ','p'),
+ $left, $left, $right,
+ // second where line
+ $right, $left, $right
+ );
+ $res = $this->_storage->queryOne($query, 'integer');
+ if (PEAR::isError($res)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $res->getMessage());
+ }
+
+ if (!$res) {
+ return false;
+ }
+
+ return $this->_prepareResult($res);
+ }
+
+ // }}}
+ // {{{ hasChildren()
+
+ /**
+ * Tells if the node with the given ID has children.
+ *
+ * @version 2003/03/04
+ * @access public
+ * @author Wolfram Kriesing <wolfram@kriesing.de>
+ * @param integer the ID of a node
+ * @return boolean if the node with the given id has children
+ */
+ function hasChildren($id)
+ {
+ $element = $this->getElement($id);
+ if (PEAR::isError($element)) {
+ return false;
+ }
+ // if the diff between left and right > 1 then there are children
+ return ($element['right'] - $element['left']) > 1;
+ }
+
+ // }}}
+ // {{{ getIdByPath()
+
+ /**
+ * return the id of the element which is referenced by $path
+ * this is useful for xml-structures, like: getIdByPath('/root/sub1/sub2')
+ * this requires the structure to use each name uniquely
+ * if this is not given it will return the first proper path found
+ * i.e. there should only be one path /x/y/z
+ * experimental: the name can be non unique if same names are in different levels
+ *
+ * @version 2003/05/11
+ * @access public
+ * @author Pierre-Alain Joye <paj@pearfr.org>
+ * @param string $path the path to search for
+ * @param integer $startId the id where to start the search
+ * @param string $nodeName the name of the key that contains
+ * the node name
+ * @param string $seperator the path seperator
+ * @return integer the id of the searched element
+ */
+ function getIdByPath($path, $startId = 0, $nodeName = 'name', $separator = '/')
+ // should this method be called getElementIdByPath ????
+ // Yes, with an optional private paramater to get the whole node
+ // in preference to only the id?
+ {
+ if ($separator == '') {
+ return Tree::raiseError(TREE_ERROR_UNKOWN_ERROR, null, null,
+ 'getIdByPath: Empty separator not allowed');
+ }
+
+ if ($path == $separator) {
+ if (Tree::isError($root = $this->getRoot())) {
+ return $root;
+ }
+ return $root['id'];
+ }
+
+ if (!($colname = $this->_getColName($nodeName))) {
+ return Tree::raiseError(TREE_ERROR_UNKOWN_ERROR, null, null,
+ 'getIdByPath: Invalid node name');
+ }
+
+ if ($startId != 0) {
+ // If the start node has no child, returns false
+ // hasChildren calls getElement. Not very good right
+ // now. See the TODO
+ $startElem = $this->getElement($startId);
+ if (Tree::isError($startElem)) {
+ return $startElem;
+ }
+
+ // No child? return
+ if (!is_array($startElem)) {
+ return null;
+ }
+
+ $rangeStart = $startElem['left'];
+ $rangeEnd = $startElem['right'];
+ // Not clean, we should call hasChildren, but I do not
+ // want to call getELement again :). See TODO
+ $startHasChild = ($rangeEnd - $rangeStart) > 1 ? true : false;
+ $cwd = '/' . $this->getPathAsString($startId);
+ } else {
+ $cwd = '/';
+ $startHasChild = false;
+ }
+
+ $t = $this->_preparePath($path, $cwd, $separator);
+ if (Tree::isError($t)) {
+ return $t;
+ }
+
+ list($elems, $sublevels) = $t;
+ $cntElems = count($elems);
+
+ $query = '
+ SELECT '
+ . $this->_getColName('id') .
+ ' FROM '
+ . $this->conf['table'] .
+ ' WHERE '
+ . $colname;
+
+ $element = $cntElems == 1 ? $elems[0] : $elems[$cntElems - 1];
+ $query .= ' = ' . $this->_storage->quote($element, 'text');
+
+ if ($startHasChild) {
+ $query .= ' AND ('.
+ $this->_getColName('left').' > '.$rangeStart.
+ ' AND '.
+ $this->_getColName('right').' < '.$rangeEnd.')';
+ }
+
+ $res = $this->_storage->queryOne($query, 'integer');
+ if (PEAR::isError($res)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $res->getMessage());
+ }
+ return $res ? (int)$res : false;
+ }
+
+ // }}}
+
+ // {{{ _getWhereAddOn()
+ /**
+ *
+ *
+ * @access private
+ * @version 2002/04/20
+ * @author Wolfram Kriesing <wolfram@kriesing.de>
+ * @param string the current where clause
+ * @return string the where clause we want to add to a query
+ */
+ function _getWhereAddOn($addAfter = ' AND ', $tableName = '')
+ {
+ if (!empty($this->conf['whereAddOn'])) {
+ return ' ' . ($tableName ? $tableName . '.' : '') . $this->conf['whereAddOn'] . $addAfter;
+ }
+ return '';
+ }
+
+ // }}}
+ // {{{ getFirstRoot()
+
+ // for compatibility to Memory methods
+ function getFirstRoot()
+ {
+ return $this->getRoot();
+ }
+
+ // }}}
+ // {{{ getBranch()
+
+ /**
+ * gets the tree under the given element in one array, sorted
+ * so you can go through the elements from begin to end and list them
+ * as they are in the tree, where every child (until the deepest) is retreived
+ *
+ * @see &_getBranch()
+ * @access public
+ * @version 2001/12/17
+ * @author Wolfram Kriesing <wolfram@kriesing.de>
+ * @param integer $startId the id where to start walking
+ * @param integer $depth this number says how deep into
+ * the structure the elements shall
+ * be retreived
+ * @return array sorted as listed in the tree
+ */
+ function &getBranch($startId = 0, $depth = 0)
+ {
+//FIXXXME use getChildren()
+ if ($startId) {
+ $startNode = $this->getElement($startId);
+ if (Tree::isError($startNode)) {
+ return $startNode;
+ }
+
+ } else {
+ }
+ }
+}
+
+/*
+ * Local Variables:
+ * mode: php
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
+?>
Property changes on: Tree/Dynamic/SQLnested.php
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
Added: svn:keywords
## -0,0 +1 ##
+Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.1
Index: Tree/Storage/SQL.php
===================================================================
--- Tree/Storage/SQL.php (.../branches/Tree_0_3_0) (revision 0)
+++ Tree/Storage/SQL.php (.../trunk) (revision 321102)
@@ -0,0 +1,77 @@
+<?php
+
+/**
+ * Require parent class definition.
+ */
+require_once 'Tree/Storage.php';
+
+class Tree_Storage_SQL extends Tree_Storage {
+ /**
+ * dsn that was connected to
+ *
+ * @var object
+ * @access private
+ */
+ var $dsn = null;
+
+ /**
+ * Database connection object.
+ *
+ * @var object
+ * @access private
+ */
+ var $dbc = null;
+
+ /**
+ * Table prefix
+ * Prefix for all db tables the container has.
+ *
+ * @var string
+ * @access public
+ */
+ var $prefix = 'liveuser_';
+
+ /**
+ * Table configuration
+ *
+ * @var array
+ * @access public
+ */
+ var $tables = array();
+
+ /**
+ * All fields with their types
+ *
+ * @var array
+ * @access public
+ */
+ var $fields = array();
+
+ /**
+ * All fields with their alias
+ *
+ * @var array
+ * @access public
+ */
+ var $alias = array();
+
+ function insert($table, $data)
+ {
+
+ }
+
+ function update($table, $data, $filters)
+ {
+
+ }
+
+ function remove($table, $filters)
+ {
+
+ }
+
+ function select()
+ {
+
+ }
+}
\ No newline at end of file
Property changes on: Tree/Storage/SQL.php
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.1
Added: svn:eol-style
## -0,0 +1 ##
+native
Index: Tree/Storage/MDB.php
===================================================================
--- Tree/Storage/MDB.php (.../branches/Tree_0_3_0) (revision 0)
+++ Tree/Storage/MDB.php (.../trunk) (revision 321102)
@@ -0,0 +1,348 @@
+<?php
+// LiveUser: A framework for authentication and authorization in PHP applications
+// Copyright (C) 2002-2003 Markus Wolff
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+/**
+ * MDB_Complex container for permission handling
+ *
+ * @package LiveUser
+ * @category authentication
+ */
+
+/**
+ * Require parent class definition.
+ */
+require_once 'Tree/Storage/SQL.php';
+require_once 'MDB.php';
+
+/**
+ * This is a PEAR::MDB backend driver for the LiveUser class.
+ * A PEAR::MDB connection object can be passed to the constructor to reuse an
+ * existing connection. Alternatively, a DSN can be passed to open a new one.
+ *
+ * Requirements:
+ * - File "Liveuser.php" (contains the parent class "LiveUser")
+ * - Array of connection options or a PEAR::MDB connection object must be
+ * passed to the constructor.
+ * Example: array('dsn' => 'mysql://user:pass@host/db_name')
+ * OR
+ * &$conn (PEAR::MDB connection object)
+ *
+ * @author Lukas Smith <smith@backendmedia.com>
+ * @author Bjoern Kraus <krausbn@php.net>
+ * @version $Id$
+ * @package LiveUser
+ * @category authentication
+ */
+class Tree_Storage_MDB extends Tree_Storage_SQL
+{
+ /**
+ * Initializes database storage container.
+ * Connects to database or uses existing database connection.
+ *
+ * @param array &$storageConf Storage Configuration
+ * @return boolean false on failure and true on success
+ *
+ * @access public
+ * @uses Tree_Storage_SQL::init
+ */
+ function init(&$storageConf)
+ {
+ if (isset($storageConf['connection']) &&
+ MDB::isConnection($storageConf['connection'])
+ ) {
+ $this->dbc = &$storageConf['connection'];
+ } elseif (isset($storageConf['dsn'])) {
+ $this->dsn = $storageConf['dsn'];
+ $function = null;
+ if (isset($storageConf['function'])) {
+ $function = $storageConf['function'];
+ }
+ $options = null;
+ if (isset($storageConf['options'])) {
+ $options = $storageConf['options'];
+ }
+ $options['optimize'] = 'portability';
+ if ($function == 'singleton') {
+ $this->dbc =& MDB::singleton($storageConf['dsn'], $options);
+ } else {
+ $this->dbc =& MDB::connect($storageConf['dsn'], $options);
+ }
+ if (PEAR::isError($this->dbc)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, 'could not create connection: '.$this->dbc->getMessage());
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Convert a text value into a DBMS specific format that is suitable to
+ * compose query statements.
+ *
+ * @param string $value text string value that is intended to be converted.
+ * @param string $type type to which the value should be converted to
+ * @return stringtext string that represents the given argument value in
+ * a DBMS specific format.
+ *
+ * @access public
+ * @uses MDB::getValue
+ */
+ function quote($value, $type)
+ {
+ return $this->dbc->getValue($type, $value);
+ }
+
+ /**
+ * Apply a type to all values of an array and return as a comma
+ * seperated string useful for generating IN statements
+ *
+ * @param array $array data array
+ * @param string $type determines type of the field
+ *
+ * @return string comma seperated values
+ *
+ * @access public
+ * @uses MDB::getValue
+ */
+ function implodeArray($array, $type)
+ {
+ if (!is_array($array) || empty($array)) {
+ return 'NULL';
+ }
+ foreach ($array as $value) {
+ $return[] = $this->dbc->getValue($type, $value);
+ }
+ return implode(', ', $return);
+ }
+
+ /**
+ * Sets the range of the next query
+ *
+ * @param string $limit number of rows to select
+ * @param string $offset first row to select
+ *
+ * @return
+ *
+ * @access public
+ * @uses MDB::setSelectedRowRange
+ */
+ function setLimit($limit, $offset)
+ {
+ if ($limit || $offset) {
+ return $this->dbc->setSelectedRowRange($offset, $limit);
+ }
+ }
+
+ /**
+ * Execute query
+ *
+ * @param string $query query
+ * @return boolean | integer
+ *
+ * @access public
+ * @uses MDB::query MDB::affectedRows
+ */
+ function query($query)
+ {
+ $result = $this->dbc->query($query);
+ if (PEAR::isError($result)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $result->getMessage() . '-' . $result->getUserInfo());
+ }
+ return $this->dbc->affectedRows();
+ }
+
+ /**
+ * Execute the specified query, fetch the value from the first column of
+ * the first row of the result set and then frees
+ * the result set.
+ *
+ * @param string $query the SELECT query statement to be executed.
+ * @param string $type argument that specifies the expected
+ * datatype of the result set field, so that an eventual conversion
+ * may be performed. The default datatype is text, meaning that no
+ * conversion is performed
+ * @return boolean | array
+ *
+ * @access public
+ * @uses MDB::queryOne
+ */
+ function queryOne($query, $type)
+ {
+ if (is_array($type)) {
+ $type = reset($type);
+ }
+ $result = $this->dbc->queryOne($query, $type);
+ if (PEAR::isError($result)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $result->getMessage() . '-' . $result->getUserInfo());
+ }
+ return $result;
+ }
+
+ /**
+ * Execute the specified query, fetch the values from the first
+ * row of the result set into an array and then frees
+ * the result set.
+ *
+ * @param string $query the SELECT query statement to be executed.
+ * @param array $type array argument that specifies a list of
+ * expected datatypes of the result set columns, so that the eventual
+ * conversions may be performed. The default list of datatypes is
+ * empty, meaning that no conversion is performed.
+ * @return boolean | array
+ *
+ * @access public
+ * @uses MDB::queryRow
+ */
+ function queryRow($query, $type)
+ {
+ $result = $this->dbc->queryRow($query, $type, MDB_FETCHMODE_ASSOC);
+ if (PEAR::isError($result)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $result->getMessage() . '-' . $result->getUserInfo());
+ }
+ return $result;
+ }
+
+ /**
+ * Execute the specified query, fetch the value from the first column of
+ * each row of the result set into an array and then frees the result set.
+ *
+ * @param string $query the SELECT query statement to be executed.
+ * @param string $type argument that specifies the expected
+ * datatype of the result set field, so that an eventual conversion
+ * may be performed. The default datatype is text, meaning that no
+ * conversion is performed
+ * @return boolean | array
+ *
+ * @access public
+ * @uses MDB::queryCol
+ */
+ function queryCol($query, $type)
+ {
+ if (is_array($type)) {
+ $type = reset($type);
+ }
+ $result = $this->dbc->queryCol($query, $type);
+ if (PEAR::isError($result)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $result->getMessage() . '-' . $result->getUserInfo());
+ }
+ return $result;
+ }
+
+ /**
+ * Execute the specified query, fetch all the rows of the result set into
+ * a two dimensional array and then frees the result set.
+ *
+ * @param string $query the SELECT query statement to be executed.
+ * @param array $types array argument that specifies a list of
+ * expected datatypes of the result set columns, so that the eventual
+ * conversions may be performed. The default list of datatypes is
+ * empty, meaning that no conversion is performed.
+ * @param boolean $rekey if set to true, the $all will have the first
+ * column as its first dimension
+ * @param boolean $group if set to true and $rekey is set to true, then
+ * all values with the same first column will be wrapped in an array
+ * @param boolean $group if set to true and $rekey is set to true, then
+ * all values with the same first column will be wrapped in an array
+ * @return boolean | array
+ *
+ * @access public
+ * @uses MDB::queryAll
+ */
+ function queryAll($query, $types, $rekey, $group)
+ {
+ $result = $this->dbc->queryAll($query, $types, MDB_FETCHMODE_ASSOC, $rekey, false, $group);
+ if (PEAR::isError($result)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $result->getMessage() . '-' . $result->getUserInfo());
+ }
+ return $result;
+ }
+
+ /**
+ * returns the next free id of a sequence
+ *
+ * @param string $seqname name of the sequence
+ * @param boolean $ondemand when true the seqence is
+ * automatic created, if it not exists
+ * @return boolean | integer
+ *
+ * @access public
+ * @uses MDB::nextId
+ */
+ function nextId($seqname, $ondemand = true)
+ {
+ $result = $this->dbc->nextId($seqname, $ondemand);
+ if (PEAR::isError($result)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $result->getMessage() . '-' . $result->getUserInfo());
+ }
+ return $result;
+ }
+
+ /**
+ * returns the next free id of a sequence if the RDBMS
+ * does not support auto increment
+ *
+ * @param string $table name of the table into which a new row was inserted
+ * @param boolean $ondemand when true the seqence is
+ * automatic created, if it not exists
+ * @return boolean | integer
+ *
+ * @access public
+ * @uses MDB::nextId
+ */
+ function getBeforeId($table, $ondemand = true)
+ {
+ $result = $this->dbc->nextId($table, $ondemand);
+ if (PEAR::isError($result)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $result->getMessage() . '-' . $result->getUserInfo());
+ }
+ return $result;
+ }
+
+ /**
+ * returns the autoincrement ID if supported or $id
+ *
+ * getAfterId isn't implemented in MDB so we return the $id that
+ * was passed by the user
+ *
+ * @param string $id value as returned by getBeforeId()
+ * @param string $table name of the table into which a new row was inserted
+ * @return integer returns the id that the users passed via params
+ *
+ * @access public
+ */
+ function getAfterId($id, $table)
+ {
+ return $id;
+ }
+
+ /**
+ *
+ * @return mixed false on error or the result
+ *
+ * @access public
+ * @uses MDB::disconnect
+ */
+ function disconnect()
+ {
+ $result = $this->dbc->disconnect();
+ if (PEAR::isError($result)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $result->getMessage() . '-' . $result->getUserInfo());
+ }
+ return $result;
+ }
+}
+?>
Property changes on: Tree/Storage/MDB.php
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.1
Added: svn:eol-style
## -0,0 +1 ##
+native
Index: Tree/Storage/MDB2.php
===================================================================
--- Tree/Storage/MDB2.php (.../branches/Tree_0_3_0) (revision 0)
+++ Tree/Storage/MDB2.php (.../trunk) (revision 321102)
@@ -0,0 +1,347 @@
+<?php
+// LiveUser: A framework for authentication and authorization in PHP applications
+// Copyright (C) 2002-2003 Markus Wolff
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+/**
+ * MDB2_Complex container for permission handling
+ *
+ * @package LiveUser
+ * @category authentication
+ */
+
+/**
+ * Require parent class definition.
+ */
+require_once 'Tree/Storage/SQL.php';
+require_once 'MDB2.php';
+
+/**
+ * This is a PEAR::MDB2 backend driver for the LiveUser class.
+ * A PEAR::MDB2 connection object can be passed to the constructor to reuse an
+ * existing connection. Alternatively, a DSN can be passed to open a new one.
+ *
+ * Requirements:
+ * - File "Liveuser.php" (contains the parent class "LiveUser")
+ * - Array of connection options or a PEAR::MDB2 connection object must be
+ * passed to the constructor.
+ * Example: array('dsn' => 'mysql://user:pass@host/db_name')
+ * OR
+ * &$conn (PEAR::MDB2 connection object)
+ *
+ * @author Lukas Smith <smith@backendmedia.com>
+ * @author Bjoern Kraus <krausbn@php.net>
+ * @version $Id$
+ * @package LiveUser
+ * @category authentication
+ */
+class Tree_Storage_MDB2 extends Tree_Storage_SQL
+{
+ var $force_seq = true;
+
+ /**
+ * Initializes database storage container.
+ * Connects to database or uses existing database connection.
+ *
+ * @param array &$storageConf Storage Configuration
+ * @return boolean false on failure and true on success
+ *
+ * @access public
+ * @uses Tree_Storage_SQL::init
+ */
+ function init(&$storageConf)
+ {
+ if (isset($storageConf['connection']) &&
+ MDB2::isConnection($storageConf['connection'])
+ ) {
+ $this->dbc = &$storageConf['connection'];
+ } elseif (isset($storageConf['dsn'])) {
+ $this->dsn = $storageConf['dsn'];
+ $function = null;
+ if (isset($storageConf['function'])) {
+ $function = $storageConf['function'];
+ }
+ $options = null;
+ if (isset($storageConf['options'])) {
+ $options = $storageConf['options'];
+ }
+ $options['portability'] = MDB2_PORTABILITY_ALL;
+ if ($function == 'singleton') {
+ $this->dbc =& MDB2::singleton($storageConf['dsn'], $options);
+ } else {
+ $this->dbc =& MDB2::connect($storageConf['dsn'], $options);
+ }
+ if (PEAR::isError($this->dbc)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, 'could not create connection: '.$this->dbc->getMessage());
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Convert a text value into a DBMS specific format that is suitable to
+ * compose query statements.
+ *
+ * @param string $value text string value that is intended to be converted.
+ * @param string $type type to which the value should be converted to
+ * @return stringtext string that represents the given argument value in
+ * a DBMS specific format.
+ *
+ * @access public
+ * @uses MDB2::quote
+ */
+ function quote($value, $type)
+ {
+ return $this->dbc->quote($value, $type);
+ }
+
+ /**
+ * Apply a type to all values of an array and return as a comma
+ * seperated string useful for generating IN statements
+ *
+ * @param array $array data array
+ * @param string $type determines type of the field
+ *
+ * @return string comma seperated values
+ *
+ * @access public
+ * @uses MDB2::implodeArray
+ */
+ function implodeArray($array, $type)
+ {
+ $this->dbc->loadModule('datatype');
+ return $this->dbc->datatype->implodeArray($array, $type);
+ }
+
+ /**
+ * Sets the range of the next query
+ *
+ * @param string $limit number of rows to select
+ * @param string $offset first row to select
+ * @return
+ *
+ * @access public
+ * @uses MDB2::setLimit
+ */
+ function setLimit($limit, $offset)
+ {
+ if ($limit || $offset) {
+ return $this->dbc->setLimit($limit, $offset);
+ }
+ }
+
+ /**
+ * Execute query
+ *
+ * @param string $query query
+ * @return boolean | integer
+ *
+ * @access public
+ * @uses MDB::query
+ */
+ function query($query)
+ {
+ $result = $this->dbc->query($query);
+ if (PEAR::isError($result)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $result->getMessage() . '-' . $result->getUserInfo());
+ }
+ return $result;
+ }
+
+ /**
+ * Execute the specified query, fetch the value from the first column of
+ * the first row of the result set and then frees
+ * the result set.
+ *
+ * @param string $query the SELECT query statement to be executed.
+ * @param string $type argument that specifies the expected
+ * datatype of the result set field, so that an eventual conversion
+ * may be performed. The default datatype is text, meaning that no
+ * conversion is performed
+ * @return boolean | array
+ *
+ * @access public
+ * @uses MDB2::queryOne
+ */
+ function queryOne($query, $type)
+ {
+ $result = $this->dbc->queryOne($query, $type);
+ if (PEAR::isError($result)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $result->getMessage() . '-' . $result->getUserInfo());
+ }
+ return $result;
+ }
+
+ /**
+ * Execute the specified query, fetch the values from the first
+ * row of the result set into an array and then frees
+ * the result set.
+ *
+ * @param string $query the SELECT query statement to be executed.
+ * @param array $type array argument that specifies a list of
+ * expected datatypes of the result set columns, so that the eventual
+ * conversions may be performed. The default list of datatypes is
+ * empty, meaning that no conversion is performed.
+ * @return boolean | array
+ *
+ * @access public
+ * @uses MDB2::queryRow
+ */
+ function queryRow($query, $type)
+ {
+ $result = $this->dbc->queryRow($query, $type, MDB2_FETCHMODE_ASSOC);
+ if (PEAR::isError($result)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $result->getMessage() . '-' . $result->getUserInfo());
+ }
+ return $result;
+ }
+
+ /**
+ * Execute the specified query, fetch the value from the first column of
+ * each row of the result set into an array and then frees the result set.
+ *
+ * @param string $query the SELECT query statement to be executed.
+ * @param string $type argument that specifies the expected
+ * datatype of the result set field, so that an eventual conversion
+ * may be performed. The default datatype is text, meaning that no
+ * conversion is performed
+ * @return boolean | array
+ *
+ * @access public
+ * @uses MDB2::queryCol
+ */
+ function queryCol($query, $type)
+ {
+ $result = $this->dbc->queryCol($query, $type);
+ if (PEAR::isError($result)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $result->getMessage() . '-' . $result->getUserInfo());
+ }
+ return $result;
+ }
+
+ /**
+ * Execute the specified query, fetch all the rows of the result set into
+ * a two dimensional array and then frees the result set.
+ *
+ * @param string $query the SELECT query statement to be executed.
+ * @param array $types array argument that specifies a list of
+ * expected datatypes of the result set columns, so that the eventual
+ * conversions may be performed. The default list of datatypes is
+ * empty, meaning that no conversion is performed.
+ * @param boolean $rekey if set to true, the $all will have the first
+ * column as its first dimension
+ * @param boolean $group if set to true and $rekey is set to true, then
+ * all values with the same first column will be wrapped in an array
+ * @param boolean $group if set to true and $rekey is set to true, then
+ * all values with the same first column will be wrapped in an array
+ * @return boolean | array
+ *
+ * @access public
+ * @uses MDB2::queryAll
+ */
+ function queryAll($query, $types, $rekey, $group)
+ {
+ $result = $this->dbc->queryAll($query, $types, MDB2_FETCHMODE_ASSOC, $rekey, false, $group);
+ if (PEAR::isError($result)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $result->getMessage() . '-' . $result->getUserInfo());
+ }
+ return $result;
+ }
+
+ /**
+ * returns the next free id of a sequence
+ *
+ * @param string $seqname name of the sequence
+ * @param boolean $ondemand when true the seqence is
+ * automatic created, if it not exists
+ * @return boolean | integer
+ *
+ * @access public
+ * @uses MDB2::nextId
+ */
+ function nextId($seqname, $ondemand = true)
+ {
+ $result = $this->dbc->nextId($seqname, $ondemand);
+ if (PEAR::isError($result)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $result->getMessage() . '-' . $result->getUserInfo());
+ }
+ return $result;
+ }
+
+ /**
+ * returns the next free id of a sequence if the RDBMS
+ * does not support auto increment
+ *
+ * @param string $table name of the table into which a new row was inserted
+ * @param boolean $ondemand when true the seqence is
+ * automatic created, if it not exists
+ * @return boolean | integer
+ *
+ * @access public
+ * @uses MDB2::nextId MDB2::getBeforeId
+ */
+ function getBeforeId($table, $ondemand = true)
+ {
+ if ($this->force_seq) {
+ $result = $this->dbc->nextId($table, $ondemand);
+ } else {
+ $result = $this->dbc->getBeforeId($table);
+ }
+ if (PEAR::isError($result)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $result->getMessage() . '-' . $result->getUserInfo());
+ }
+ return $result;
+ }
+
+ /**
+ * returns the autoincrement ID if supported or $id
+ *
+ * @param string $id value as returned by getBeforeId()
+ * @param string $table name of the table into which a new row was inserted
+ * @return boolean | integer returns the id that the users passed via params
+ *
+ * @access public
+ * @uses MDB2::getAfterId
+ */
+ function getAfterId($id, $table)
+ {
+ if ($this->force_seq) {
+ return $id;
+ }
+ $result = $this->dbc->getAfterId($id, $table);
+ if (PEAR::isError($result)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $result->getMessage() . '-' . $result->getUserInfo());
+ }
+ return $result;
+ }
+
+ /**
+ *
+ * @return mixed false on error or the result
+ *
+ * @access public
+ * @uses MDB2::disconnect
+ */
+ function disconnect()
+ {
+ $result = $this->dbc->disconnect();
+ if (PEAR::isError($result)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $result->getMessage() . '-' . $result->getUserInfo());
+ }
+ return $result;
+ }
+}
+?>
Property changes on: Tree/Storage/MDB2.php
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.1
Added: svn:eol-style
## -0,0 +1 ##
+native
Index: Tree/Storage/DB.php
===================================================================
--- Tree/Storage/DB.php (.../branches/Tree_0_3_0) (revision 0)
+++ Tree/Storage/DB.php (.../trunk) (revision 321102)
@@ -0,0 +1,334 @@
+<?php
+// LiveUser: A framework for authentication and authorization in PHP applications
+// Copyright (C) 2002-2003 Markus Wolff
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+/**
+ * DB_Complex container for permission handling
+ *
+ * @package LiveUser
+ * @category authentication
+ */
+
+/**
+ * Require parent class definition.
+ */
+require_once 'Tree/Storage/SQL.php';
+require_once 'DB.php';
+
+/**
+ * This is a PEAR::DB backend driver for the LiveUser class.
+ * A PEAR::DB connection object can be passed to the constructor to reuse an
+ * existing connection. Alternatively, a DSN can be passed to open a new one.
+ *
+ * Requirements:
+ * - File "Liveuser.php" (contains the parent class "LiveUser")
+ * - Array of connection options or a PEAR::DB connection object must be
+ * passed to the constructor.
+ * Example: array('dsn' => 'mysql://user:pass@host/db_name')
+ * OR
+ * &$conn (PEAR::DB connection object)
+ *
+ * @author Lukas Smith <smith@backendmedia.com>
+ * @author Bjoern Kraus <krausbn@php.net>
+ * @version $Id$
+ * @package Tree
+ * @category Structurs
+ */
+class Tree_Storage_DB extends Tree_Storage_SQL
+{
+ /**
+ * Initializes database storage container.
+ * Connects to database or uses existing database connection.
+ *
+ * @param array &$storageConf Storage Configuration
+ * @return boolean false on failure and true on success
+ *
+ * @access public
+ * @uses Tree_Storage_SQL::init
+ */
+ function init(&$storageConf)
+ {
+ if (isset($storageConf['connection']) &&
+ DB::isConnection($storageConf['connection'])
+ ) {
+ $this->dbc = &$storageConf['connection'];
+ } elseif (isset($storageConf['dsn'])) {
+ $this->dsn = $storageConf['dsn'];
+ $options = null;
+ if (isset($storageConf['options'])) {
+ $options = $storageConf['options'];
+ }
+ $options['portability'] = DB_PORTABILITY_ALL;
+ $this->dbc =& DB::connect($storageConf['dsn'], $options);
+ if (PEAR::isError($this->dbc)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, 'could not create connection: '.$this->dbc->getMessage());
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Convert a text value into a DBMS specific format that is suitable to
+ * compose query statements.
+ *
+ * @param string $value text string value that is intended to be converted.
+ * @param string $type type to which the value should be converted to
+ * @return stringtext string that represents the given argument value in
+ * a DBMS specific format.
+ *
+ * @access public
+ * @uses DB::quoteSmart
+ */
+ function quote($value, $type)
+ {
+ return $this->dbc->quoteSmart($value);
+ }
+
+ /**
+ *
+ * @param array $array
+ * @param string $type
+ * @return string
+ *
+ * @access public
+ * @uses DB::quoteSmart
+ */
+ function implodeArray($array, $type)
+ {
+ if (!is_array($array) || empty($array)) {
+ return 'NULL';
+ }
+ foreach ($array as $value) {
+ $return[] = $this->dbc->quoteSmart($value);
+ }
+ return implode(', ', $return);
+ }
+
+ /**
+ * This function is not implemented into DB so we
+ * can't make use of it.
+ *
+ * @param string $limit
+ * @param string $offset
+ * @return boolean false This feature isn't supported by DB
+ *
+ * @access public
+ */
+ function setLimit($limit, $offset)
+ {
+ if ($limit || $offset) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, 'limit is not supported by this backend');
+ }
+ }
+
+ /**
+ * Execute query
+ *
+ * @param string $query query
+ * @return boolean | integer
+ *
+ * @access public
+ * @uses DB::query DB::affectedRows
+ */
+ function query($query)
+ {
+ $result = $this->dbc->query($query);
+ if (PEAR::isError($result)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $result->getMessage() . '-' . $result->getUserInfo());
+ }
+ return $this->dbc->affectedRows();
+ }
+
+ /**
+ * Execute the specified query, fetch the value from the first column of
+ * the first row of the result set and then frees
+ * the result set.
+ *
+ * @param string $query the SELECT query statement to be executed.
+ * @param string $type argument that specifies the expected
+ * datatype of the result set field, so that an eventual conversion
+ * may be performed. The default datatype is text, meaning that no
+ * conversion is performed
+ * @return boolean | array
+ *
+ * @access public
+ * @uses DB::getOne
+ */
+ function queryOne($query, $type)
+ {
+ $result = $this->dbc->getOne($query);
+ if (PEAR::isError($result)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $result->getMessage() . '-' . $result->getUserInfo());
+ }
+ return $result;
+ }
+
+ /**
+ * Execute the specified query, fetch the values from the first
+ * row of the result set into an array and then frees
+ * the result set.
+ *
+ * @param string $query the SELECT query statement to be executed.
+ * @param array $type array argument that specifies a list of
+ * expected datatypes of the result set columns, so that the eventual
+ * conversions may be performed. The default list of datatypes is
+ * empty, meaning that no conversion is performed.
+ * @return boolean | array
+ *
+ * @access public
+ * @uses DB::getRow
+ */
+ function queryRow($query, $type)
+ {
+ $result = $this->dbc->getRow($query, null, DB_FETCHMODE_ASSOC);
+ if (PEAR::isError($result)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $result->getMessage() . '-' . $result->getUserInfo());
+ }
+ return $result;
+ }
+
+ /**
+ * Execute the specified query, fetch the value from the first column of
+ * each row of the result set into an array and then frees the result set.
+ *
+ * @param string $query the SELECT query statement to be executed.
+ * @param string $type argument that specifies the expected
+ * datatype of the result set field, so that an eventual conversion
+ * may be performed. The default datatype is text, meaning that no
+ * conversion is performed
+ * @return boolean | array
+ *
+ * @access public
+ * @uses DB::getCol
+ */
+ function queryCol($query, $type)
+ {
+ $result = $this->dbc->getCol($query);
+ if (PEAR::isError($result)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $result->getMessage() . '-' . $result->getUserInfo());
+ }
+ return $result;
+ }
+
+ /**
+ * Execute the specified query, fetch all the rows of the result set into
+ * a two dimensional array and then frees the result set.
+ *
+ * @param string $query the SELECT query statement to be executed.
+ * @param array $types array argument that specifies a list of
+ * expected datatypes of the result set columns, so that the eventual
+ * conversions may be performed. The default list of datatypes is
+ * empty, meaning that no conversion is performed.
+ * @param boolean $rekey if set to true, the $all will have the first
+ * column as its first dimension
+ * @param boolean $group if set to true and $rekey is set to true, then
+ * all values with the same first column will be wrapped in an array
+ * @param boolean $group if set to true and $rekey is set to true, then
+ * all values with the same first column will be wrapped in an array
+ * @return boolean | array
+ *
+ * @access public
+ * @uses DB::getAll DB::getAssoc
+ */
+ function queryAll($query, $types, $rekey, $group)
+ {
+ if ($rekey) {
+ $result = $this->dbc->getAssoc($query, false, array(), DB_FETCHMODE_ASSOC, $group);
+ } else {
+ $result = $this->dbc->getAll($query, array(), DB_FETCHMODE_ASSOC);
+ }
+ if (PEAR::isError($result)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $result->getMessage() . '-' . $result->getUserInfo());
+ }
+ return $result;
+ }
+
+ /**
+ * returns the next free id of a sequence
+ *
+ * @param string $seqname name of the sequence
+ * @param boolean $ondemand when true the seqence is
+ * automatic created, if it not exists
+ * @return boolean | integer false on failure or next id for the table
+ *
+ * @access public
+ * @uses DB::nextId
+ */
+ function nextId($seqname, $ondemand = true)
+ {
+ $result = $this->dbc->nextId($seqname, $ondemand);
+ if (PEAR::isError($result)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $result->getMessage() . '-' . $result->getUserInfo());
+ }
+ return $result;
+ }
+
+ /**
+ * returns the next free id of a sequence if the RDBMS
+ * does not support auto increment
+ *
+ * @param string $table name of the table into which a new row was inserted
+ * @param boolean $ondemand when true the seqence is
+ * automatic created, if it not exists
+ * @return boolean | integer
+ *
+ * @access public
+ * @uses DB::nextId
+ */
+ function getBeforeId($table, $ondemand = true)
+ {
+ $result = $this->dbc->nextId($table, $ondemand);
+ if (PEAR::isError($result)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $result->getMessage() . '-' . $result->getUserInfo());
+ }
+ return $result;
+ }
+
+ /**
+ * returns the autoincrement ID if supported or $id
+ *
+ * getAfterId isn't implemented in DB so we return the $id that
+ * was passed by the user
+ *
+ * @param string $id value as returned by getBeforeId()
+ * @param string $table name of the table into which a new row was inserted
+ * @return integer returns the id that the users passed via params
+ *
+ * @access public
+ */
+ function getAfterId($id, $table)
+ {
+ return $id;
+ }
+
+ /**
+ *
+ * @return mixed false on error or the result
+ *
+ * @access public
+ * @uses DB::disconnect
+ */
+ function disconnect()
+ {
+ $result = $this->dbc->disconnect();
+ if (PEAR::isError($result)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $result->getMessage() . '-' . $result->getUserInfo());
+ }
+ return $result;
+ }
+}
+?>
Property changes on: Tree/Storage/DB.php
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.1
Added: svn:eol-style
## -0,0 +1 ##
+native
Index: Tree/Tree.php
===================================================================
--- Tree/Tree.php (.../branches/Tree_0_3_0) (revision 321102)
+++ Tree/Tree.php (.../trunk) (revision 321102)
@@ -3,12 +3,12 @@
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2004 The PHP Group |
+// | Copyright (c) 1997-2005 The PHP Group |
// +----------------------------------------------------------------------+
-// | This source file is subject to version 2.02 of the PHP license, |
+// | This source file is subject to version 3.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. |
+// | http://www.php.net/license/3_0.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. |
@@ -19,6 +19,12 @@
// $Id$
/**
+ * Include PEAR
+ */
+
+require_once 'PEAR.php';
+
+/**
* the DB interface to the tree class
*
* @access public
@@ -26,11 +32,92 @@
* @version 2001/06/27
* @package Tree
*/
+
+define('TREE_ERROR', -1);
+define('TREE_ERROR_NOT_IMPLEMENTED', -2);
+define('TREE_ERROR_ELEMENT_NOT_FOUND', -3);
+define('TREE_ERROR_INVALID_NODE_NAME', -4);
+define('TREE_ERROR_MOVE_TO_CHILDREN', -5);
+define('TREE_ERROR_PARENT_ID_MISSED', -6);
+define('TREE_ERROR_INVALID_PARENT', -7);
+define('TREE_ERROR_EMPTY_PATH', -8);
+define('TREE_ERROR_INVALID_PATH', -9);
+define('TREE_ERROR_DB_ERROR', -10);
+define('TREE_ERROR_PATH_SEPARATOR_EMPTY', -11);
+define('TREE_ERROR_CANNOT_CREATE_FOLDER', -12);
+define('TREE_ERROR_UNKOWN_ERROR', -13);
+
+
class Tree
{
- // {{{ setupMemory()
+ /**
+ * @var array you need to overwrite this array and give the keys/
+ * that are allowed
+ */
+ var $_forceSetOption = false;
/**
+ * put proper value-keys are given in each class, depending
+ * on the implementation only some options are needed or allowed,
+ * see the classes which extend this one
+ *
+ * @access public
+ * @var array saves the options passed to the constructor
+ */
+ var $conf = array(
+ 'whereAddOn' => '',
+ 'table' => '',
+ // since the internal names are fixed, to be portable between different
+ // DB tables with different column namings, we map the internal name
+ // to the real column name using this array here, if it stays empty
+ // the internal names are used, which are:
+ // id, left, right
+ 'fields' => array(
+ 'id' => array('type' => 'integer', 'name' => 'id'),
+ 'name' => array('type' => 'text', 'name' => 'name'),
+ // since mysql at least doesnt support 'left' ...
+ 'left' => array('type' => 'text', 'name' => 'l'),
+ // ...as a column name we set default to the first
+ //letter only
+ 'right' => array('type' => 'text', 'name' => 'r'),
+ // parent id
+ 'parent_id' => array('type' => 'integer', 'name' => 'parent')
+ ),
+ 'order' => 'id'
+ );
+
+ /**
+ * Storage Container
+ *
+ * @var object
+ */
+ var $_storage = null;
+
+ /**
+ * Factory
+ *
+ * @static
+ * @access public
+ * @return object
+ * @param string
+ * @param string
+ * @param array
+ */
+/* function &factory($type = 'Simple', $container = 'MDB2', $options = array())
+ {
+ $type = ucfirst(strtolower($type));
+ $container = strtoupper($container);
+ $class = 'Tree_'. $type .'_'. $container;
+ require_once strtr($class, '_', '/') .'.php';
+ $tree = &new $class($options);
+ if (Tree::isError($e = $tree->setup($options))) {
+ return $e;
+ }
+ return $tree;
+ }
+*/
+
+ /**
* setup an object which works on trees that are temporarily saved in
* memory dont use with huge trees, suggested is a maximum size of tree
* of 1000-5000 elements since the entire tree is read at once
@@ -58,19 +145,16 @@
* @param mixed the dsn, or filename, etc., empty i.e. for XML
* if you use setupByRawData
*/
- function &setupMemory($type, $dsn = '', $options = array())
+ function &factoryMemory($config)
{
// if anyone knows a better name it would be great to change it.
// since "setupMemory" kind of reflects it but i think it's not obvious
// if you dont know what is meant
include_once 'Tree/Memory.php';
- $memory = &new Tree_Memory($type, $dsn, $options);
+ $memory = new Tree_Memory($config);
return $memory;
}
- // }}}
- // {{{ setupDynamic()
-
/**
* setup an object that works on trees where each element(s) are read
* on demand from the given data source actually this was intended to serve
@@ -89,19 +173,23 @@
* it would be the filename
* @param array the options you want to set
*/
- function &setupDynamic($type, $dsn, $options = array())
+ function &factoryDynamic($config)
{
// "dynamic" stands for retreiving a tree(chunk) dynamically when needed,
// better name would be great :-)
- include_once "Tree/Dynamic/$type.php";
- $className = 'Tree_Dynamic_'.$type;
- $obj = & new $className($dsn, $options);
- return $obj;
+ if (in_array(strtoupper($config['storage']['name']), array('DB', 'MDB', 'MDB2'))) {
+ $name = 'SQL';
+ } else {
+ $name = strtoupper($config['storage']['name']);
+ }
+
+ $name .= strtolower($config['type']);
+ include_once "Tree/Dynamic/$name.php";
+ $className = 'Tree_Dynamic_' . $name;
+ $dynamic = new $className($config);
+ return $dynamic;
}
- // }}}
- // {{{ setup()
-
/**
* this is just a wrapper around the two setup methods above
* some example calls:
@@ -145,31 +233,883 @@
* for XML it would be the filename
* @param array the options you want to set
*/
- function setup($type, $dsn = '', $options = array())
+ function &factory($config)
{
- $type = explode('_', $type);
- $method = 'setup'.$type[0];
- return Tree::$method($type[1], $dsn, $options);
+ if (!isset($config['container'])) {
+ return Tree::raiseError(TREE_ERROR, null, null, 'Config option container wasn\t set.');
+ }
+ $method = 'factory' . $config['container'];
+ return Tree::$method($config);
}
- // }}}
+ /**
+ * Returns an instance of a storage Container
+ *
+ * @param array configuration array to pass to the storage container
+ * @param string $classprefix Prefix of the class that will be used.
+ * @return object|false will return an instance of a Storage container
+ * or false upon error
+ *
+ * @author LiveUser
+ * @access protected
+ */
+ function &storageFactory(&$confArray, $classprefix = 'Tree_')
+ {
+ $storageName = $classprefix . 'Storage_' . $confArray['name'];
+ if (!Tree::loadClass($storageName) && count($confArray) <= 1) {
+ $return = false;
+ return $return;
+ // if the storage container does not exist try the next one in the stack
+ }
+
+ $storage = new $storageName();
+ if (PEAR::isError($storage->init($confArray))) {
+ $return = false;
+ return $return;
+ }
+
+ return $storage;
+ }
+
+ /**
+ * Load the storage container
+ *
+ * @access public
+ * @param mixed Name of array containing the configuration.
+ * @return boolean true on success or false on failure
+ */
+ function init($conf)
+ {
+ if (!isset($conf['storage'])) {
+ return Tree::raiseError(TREE_ERROR, null, null, 'Missing storage configuration array');
+ }
+
+ if (is_array($conf)) {
+ $keys = array_keys($conf);
+ foreach ($keys as $key) {
+ if (isset($this->$key)) {
+ $this->$key =& $conf[$key];
+ }
+ }
+ }
+
+ $this->_storage = Tree::storageFactory($conf['storage']);
+ if ($this->_storage === false) {
+ return Tree::raiseError(TREE_ERROR, null, null, 'Could not instanciate storage container');
+ }
+
+ return true;
+ }
+
+ /**
+ * Loads a PEAR class.
+ *
+ * @param string classname to load
+ * @param bool if errors should be supressed from the stack
+ * @return bool true success or false on failure
+ *
+ * @access public
+ */
+ function loadClass($classname, $supress_error = false)
+ {
+ if (!Tree::classExists($classname)) {
+ $filename = str_replace('_', '/', $classname).'.php';
+ @include_once($filename);
+ if (!Tree::classExists($classname) && !$supress_error) {
+ if (!Tree::fileExists($filename)) {
+ $msg = 'File for the class does not exist ' . $classname;
+ } else {
+ $msg = 'Parse error in the file for class' . $classname;
+ }
+// PEAR_ErrorStack::staticPush('LiveUser', LIVEUSER_ERROR_CONFIG,
+// 'exception', array(), $msg);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Checks if a file exists in the include path.
+ *
+ * @param string filename
+ * @return bool true success and false on error
+ *
+ * @access public
+ */
+ function fileExists($filename)
+ {
+ // safe_mode does notwork with is_readable()
+ if (ini_get('safe_mode')) {
+ $fp = @fopen($file, 'r', true);
+ if (is_resource($fp)) {
+ @fclose($fp);
+ return true;
+ }
+ } else {
+ $dirs = explode(PATH_SEPARATOR, ini_get('include_path'));
+ foreach ($dirs as $dir) {
+ if (is_readable($dir . DIRECTORY_SEPARATOR . $file)) {
+ return true;
+ }
+ }
+ }
+ }
+
+ /**
+ * Checks if a class exists without triggering __autoload
+ *
+ * @param string classname
+ * @return bool true success and false on error
+ *
+ * @access public
+ */
+ function classExists($classname)
+ {
+ if (version_compare(phpversion(), '5.0', '>=')) {
+ return class_exists($classname, false);
+ }
+ return class_exists($classname);
+ }
+
+ /**
+ * Clobbers two arrays together.
+ *
+ * Function taken from the user notes of array_merge_recursive function
+ * and may be called statically
+ *
+ * @param array array that should be clobbered
+ * @param array array that should be clobbered
+ * @return array|false array on success and false on error
+ *
+ * @access public
+ * @author kc@hireability.com
+ */
+ function arrayMergeClobber($a1, $a2)
+ {
+ if (!is_array($a1) || !is_array($a2)) {
+ return false;
+ }
+ foreach ($a2 as $key => $val) {
+ if (is_array($val) && array_key_exists($key, $a1) && is_array($a1[$key])) {
+ $a1[$key] = Tree::arrayMergeClobber($a1[$key], $val);
+ } else {
+ $a1[$key] = $val;
+ }
+ }
+ return $a1;
+ }
+
+ /**
+ * This method is used to communicate an error and invoke error
+ * callbacks etc. Basically a wrapper for PEAR::raiseError
+ * without the message string.
+ *
+ * @param mixed integer error code, or a PEAR error object (all
+ * other parameters are ignored if this parameter is
+ * an object
+ *
+ * @param int error mode, see PEAR_Error docs
+ *
+ * @param mixed If error mode is PEAR_ERROR_TRIGGER, this is the
+ * error level (E_USER_NOTICE etc). If error mode is
+ * PEAR_ERROR_CALLBACK, this is the callback function,
+ * either as a function name, or as an array of an
+ * object and method name. For other error modes this
+ * parameter is ignored
+ * @param string Extra debug information. Defaults to the last
+ * query and native error code.
+ *
+ * @return object a PEAR error object
+ *
+ * @see PEAR_Error
+ */
+ function &raiseError($code = null, $mode = null, $options = null, $userinfo = null)
+ {
+ $tmp = PEAR::raiseError(null, $code, $mode, $options, $userinfo, 'Tree_Error', true);
+ return $tmp;
+ }
+
+ /**
+ * Return a textual error message for a MDB2 error code
+ *
+ * @param int|array $value integer error code,
+ null to get the current error code-message map,
+ or an array with a new error code-message map
+ * @return string error message, or false if the error code was
+ * not recognized
+ * @access public
+ */
+ function errorMessage($value = null)
+ {
+ // make the variable static so that it only has to do the defining on the first call
+ static $errorMessages;
+
+ // define the varies error messages
+ if (is_array($value)) {
+ $errorMessages = $value;
+ return MDB2_OK;
+ } elseif (!isset($errorMessages)) {
+ $errorMessages = array(
+ TREE_ERROR => 'Unkown error',
+ TREE_ERROR_NOT_IMPLEMENTED => 'This method is currently not implemented',
+ TREE_ERROR_INVALID_PATH => 'Invalid Path',
+ TREE_ERROR_DB_ERROR => 'Database error',
+ TREE_ERROR_PARENT_ID_MISSED => 'Parent ID is missing',
+ TREE_ERROR_MOVE_TO_CHILDREN => 'Move to children',
+ TREE_ERROR_ELEMENT_NOT_FOUND => 'Element not found',
+ TREE_ERROR_PATH_SEPARATOR_EMPTY => 'Path separator empty',
+ TREE_ERROR_INVALID_NODE_NAME => 'Invalid node name',
+ TREE_ERROR_UNKOWN_ERROR => 'Unkown error',
+ );
+ }
+
+ if (is_null($value)) {
+ return $errorMessages;
+ }
+
+ // If this is an error object, then grab the corresponding error code
+ if (PEAR::isError($value)) {
+ $value = $value->getCode();
+ }
+
+ // return the textual error message corresponding to the code
+ return isset($errorMessages[$value]) ? $errorMessages[$value] :
+ $errorMessages[TREE_ERROR];
+ }
+
// {{{ isError()
/**
- * Tell whether a result code from a DB method is an error
- *
- * @param int result code
- *
- * @return bool whether $value is an error
- *
- * @access public
- */
- function isError($value)
+ * Tell whether a value is a Tree error.
+ *
+ * @param mixed $data the value to test
+ * @param int $code if $data is an error object, return true
+ * only if $code is a string and
+ * $obj->getMessage() == $code or
+ * $code is an integer and $obj->getCode() == $code
+ * @access public
+ * @return bool true if parameter is an error
+ */
+ function isError($data, $code = null)
{
- return (is_object($value) &&
- (is_a($value, 'tree_error') ||
- is_subclass_of($value, 'tree_error')));
+ if (is_a($data, 'Tree_Error')) {
+ if (is_null($code)) {
+ return true;
+ } elseif (is_string($code)) {
+ return $data->getMessage() == $code;
+ } else {
+ $code = (array)$code;
+ return in_array($data->getCode(), $code);
+ }
+ }
+
+ return false;
}
// }}}
-}
\ No newline at end of file
+
+ // {{{ getChildrenIds()
+
+ /**
+ * get the ids of the children of the given element
+ *
+ * @version 2002/02/06
+ * @access public
+ * @author Wolfram Kriesing <wolfram@kriesing.de>
+ * @param integer ID of the element that the children shall be
+ * retreived for
+ * @param integer how many levels deep into the tree
+ * @return mixed an array of all the ids of the children of the element
+ * with id=$id, or false if there are no children
+ */
+ function getChildrenIds($id, $levels = 1)
+ {
+ // returns false if no children exist
+ if (!($children = $this->getChildren($id, $levels))) {
+ return array();
+ }
+ // return an empty array, if you want to know
+ // if there are children, use hasChildren
+ if ($children && count($children)) {
+ foreach ($children as $aChild) {
+ $childrenIds[] = $aChild['id'];
+ }
+ }
+
+ return $childrenIds;
+ }
+
+ // }}}
+ // {{{ getAllChildren()
+
+ /**
+ * gets all the children and grand children etc.
+ *
+ * @version 2002/09/30
+ * @access public
+ * @author Wolfram Kriesing <wolfram@kriesing.de>
+ * @param integer ID of the element that the children shall be
+ * retreived for
+ *
+ * @return mixed an array of all the children of the element with
+ * id=$id, or false if there are no children
+ */
+ // FIXXXME remove this method and replace it by getChildren($id,0)
+ function getAllChildren($id)
+ {
+ $retChildren = false;
+ if ($children = $this->hasChildren($id)) {
+ $retChildren = $this->_getAllChildren($id);
+ }
+
+ return $retChildren;
+ }
+
+ // }}}
+ // {{{ _getAllChildren()
+
+ /**
+ * this method gets all the children recursively
+ *
+ * @see getAllChildren()
+ * @version 2002/09/30
+ * @access public
+ * @author Wolfram Kriesing <wolfram@kriesing.de>
+ * @param integer ID of the element that the children shall be
+ * retreived for
+ *
+ * @return mixed an array of all the ids of the children of the element
+ * with id=$id, or false if there are no children
+ */
+ function &_getAllChildren($id)
+ {
+ $retChildren = array();
+ if ($children = $this->getChildren($id)) {
+ foreach ($children as $key => $child) {
+ $retChildren[] = &$children[$key];
+ $retChildren = array_merge($retChildren,
+ $this->_getAllChildren($child['id']));
+ }
+ }
+
+ return $retChildren;
+ }
+
+ // }}}
+ // {{{ getAllChildrenIds()
+
+ /**
+ * gets all the children-ids and grand children-ids
+ *
+ * @version 2002/09/30
+ * @access public
+ * @author Kriesing <wolfram@kriesing.de>
+ * @param integer ID of the element that the children shall
+ * be retreived for
+ *
+ * @return mixed an array of all the ids of the children of the element
+ * with id=$id,
+ * or false if there are no children
+ */
+ function getAllChildrenIds($id)
+ {
+ $childrenIds = array();
+ if ($allChildren = $this->getAllChildren($id)) {
+ $childrenIds = array();
+ foreach ($allChildren as $node) {
+ $childrenIds[] = $node['id'];
+ }
+ }
+
+ return $childrenIds;
+ }
+
+ // }}}
+ // {{{ getParents()
+
+ /**
+ * this gets all the preceeding nodes, the parent and it's parent and so on
+ *
+ * @version 2002/08/19
+ * @access public
+ * @author Wolfram Kriesing <wolfram@kriesing.de>
+ * @param integer the id of the element for which the parent_id shall
+ * be retreived
+ * @return array of the parent nodes including the node with id $id
+ */
+ function getParents($id)
+ {
+ $path = $this->getPath($id);
+ $parents = array();
+ if (count($path)) {
+ foreach ($path as $node) {
+ $parents[] = $node;
+ }
+ }
+
+ return $parents;
+ }
+
+ // }}}
+ // {{{ getParentsIds()
+
+ /**
+ * get the ids of the parents and all it's parents and so on
+ * it simply returns the ids of the elements returned by getParents()
+ *
+ * @see getParents()
+ * @version 2002/08/19
+ * @access public
+ * @author Wolfram Kriesing <wolfram@kriesing.de>
+ * @param integer $id the id of the element for which the parent_id
+ * shall be retreived
+ *
+ * @return array of the ids
+ */
+ function getParentsIds($id)
+ {
+ $parents = $this->getParents($id);
+ $parentsIds = array();
+ if (count($parents)) {
+ foreach ($parents as $node) {
+ $parentsIds[] = $node['id'];
+ }
+ }
+
+ return $parentsIds;
+ }
+
+ // }}}
+ // {{{ getPathAsString()
+
+ /**
+ * returns the path as a string
+ *
+ * @access public
+ * @version 2002/03/28
+ * @access public
+ * @author Wolfram Kriesing <wolfram@kriesing.de>
+ * @param mixed $id the id of the node to get the path for
+ * @param integer If offset is positive, the sequence will
+ * start at that offset in the array . If
+ * offset is negative, the sequence will start that far
+ * from the end of the array.
+ * @param integer If length is given and is positive, then
+ * the sequence will have that many elements in it. If
+ * length is given and is negative then the
+ * sequence will stop that many elements from the end of
+ * the array. If it is omitted, then the sequence will
+ * have everything from offset up until the end
+ * of the array.
+ * @param string you can tell the key the path shall be used to be
+ * constructed with i.e. giving 'name' (=default) would
+ * use the value of the $element['name'] for the node-name
+ * (thanks to Michael Johnson).
+ *
+ * @return array this array contains all elements from the root
+ * to the element given by the id
+ */
+ function getPathAsString($id, $seperator = '/',
+ $offset = 0, $length = 0, $key = 'name')
+ {
+ $path = $this->getPath($id);
+ foreach ($path as $aNode) {
+ $pathArray[] = $aNode[$key];
+ }
+
+ if ($offset) {
+ if ($length) {
+ $pathArray = array_slice($pathArray, $offset, $length);
+ } else {
+ $pathArray = array_slice($pathArray, $offset);
+ }
+ }
+
+ $pathString = '';
+ if (count($pathArray)) {
+ $pathString = implode($seperator, $pathArray);
+ }
+
+ return $pathString;
+ }
+
+ // }}}
+
+
+ //
+ // abstract methods, those should be overwritten by the implementing class
+ //
+
+ // {{{ getPath()
+
+ /**
+ * gets the path to the element given by its id
+ *
+ * @abstract
+ * @version 2001/10/10
+ * @access public
+ * @author Wolfram Kriesing <wolfram@kriesing.de>
+ * @param mixed $id the id of the node to get the path for
+ * @return array this array contains all elements from the root
+ * to the element given by the id
+ */
+ function getPath($id)
+ {
+ return Tree::raiseError('TREE_ERROR_NOT_IMPLEMENTED');
+ }
+
+ // }}}
+ // {{{ getLevel()
+
+ /**
+ * get the level, which is how far below the root the element
+ * with the given id is
+ *
+ * @abstract
+ * @version 2001/11/25
+ * @access public
+ * @author Wolfram Kriesing <wolfram@kriesing.de>
+ * @param mixed $id the id of the node to get the level for
+ *
+ */
+ function getLevel($id)
+ {
+ return Tree::raiseError('TREE_ERROR_NOT_IMPLEMENTED');
+ }
+
+ // }}}
+ // {{{ isChildOf()
+
+ /**
+ * returns if $childId is a child of $id
+ *
+ * @abstract
+ * @version 2002/04/29
+ * @access public
+ * @author Wolfram Kriesing <wolfram@kriesing.de>
+ * @param int id of the element
+ * @param int id of the element to check if it is a child
+ * @param boolean if this is true the entire tree below is checked
+ * @return boolean true if it is a child
+ */
+ function isChildOf($id, $childId, $checkAll = true)
+ {
+ return Tree::raiseError('TREE_ERROR_NOT_IMPLEMENTED');
+ }
+
+ // }}}
+ // {{{ getIdByPath()
+
+ /**
+ *
+ *
+ */
+ function getIdByPath($path, $startId = 0, $nodeName = 'name', $seperator = '/')
+ {
+ return Tree::raiseError('TREE_ERROR_NOT_IMPLEMENTED');
+ }
+
+ // }}}
+ // {{{ getDepth()
+
+ /**
+ * return the maximum depth of the tree
+ *
+ * @version 2003/02/25
+ * @access public
+ * @author Wolfram Kriesing <wolfram@kriesing.de>
+ * @return int the depth of the tree
+ */
+ function getDepth()
+ {
+ return $this->_treeDepth;
+ }
+
+ // }}}
+
+ //
+ // PRIVATE METHODS
+ //
+
+ // {{{ _preparePath()
+
+ /**
+ * gets the path to the element given by its id
+ *
+ * @version 2003/05/11
+ * @access private
+ * @author Wolfram Kriesing <wolfram@kriesing.de>
+ * @param mixed $id the id of the node to get the path for
+ * @return array this array contains the path elements and the sublevels
+ * to substract if no $cwd has been given.
+ */
+ function _preparePath($path, $cwd = '/', $separator = '/')
+ {
+ $elems = explode($separator, $path);
+ $cntElems = count($elems);
+
+ // beginning with a slash
+ if (empty($elems[0])) {
+ $beginSlash = true;
+ array_shift($elems);
+ --$cntElems;
+ }
+
+ // ending with a slash
+ if (empty($elems[$cntElems - 1])) {
+ $endSlash = true;
+ array_pop($elems);
+ --$cntElems;
+ }
+
+ // Get the real path, and the levels
+ // to substract if required
+ $down = 0;
+ while ($elems[0] == '..') {
+ array_shift($elems);
+ ++$down;
+ }
+
+ if ($down >= 0 && $cwd == '/') {
+ $down = 0;
+ $_elems = array();
+ $sublevel = 0;
+ $_elems = array();
+ } else {
+ list($_elems, $sublevel) = $this->_preparePath($cwd);
+ }
+
+ $i = 0;
+ foreach ($elems as $val) {
+ if (trim($val) == '') {
+ return Tree::raiseError('TREE_ERROR_INVALID_PATH');
+ }
+
+ if ($val == '..') {
+ $i == 0 ? ++$down : --$i;
+ } else {
+ $_elems[++$i] = $val;
+ }
+ }
+
+ if (count($_elems) < 1) {
+ return Tree::raiseError('TREE_ERROR_EMPTY_PATH');
+ }
+
+ return array($_elems, $sublevel);
+ }
+
+ // }}}
+ // {{{ _prepareResults()
+
+ /**
+ * prepare multiple results
+ *
+ * @see _prepareResult()
+ * @access private
+ * @version 2002/03/03
+ * @author Wolfram Kriesing <wolfram@kriesing.de>
+ * @param array the data to prepare
+ * @return array prepared results
+ */
+ function _prepareResults($results)
+ {
+ $nResults = array();
+ foreach ($results as $key => $value) {
+ $nResults[$key] = $this->_prepareResult($value);
+ }
+
+ return $nResults;
+ }
+ // }}}
+ // {{{ _prepareResult()
+
+ /**
+ * map back the index names to get what is expected
+ *
+ * @access private
+ * @version 2002/03/03
+ * @author Wolfram Kriesing <wolfram@kriesing.de>
+ * @param array a result
+ * @return array the prepared result
+ */
+ function _prepareResult($result)
+ {
+ if (isset($this->conf['fields'])) {
+ foreach ($this->conf['fields'] as $key => $columnName) {
+ if (isset($result[$columnName['name']]) && $key != $columnName['name']) {
+ $result[$key] = $result[$columnName['name']];
+ unset($result[$columnName['name']]);
+ }
+ }
+ }
+
+ return $result;
+ }
+
+ // }}}
+ // {{{ _getColName()
+
+ /**
+ * this method retrieves the real column name, as used in the DB
+ * since the internal names are fixed, to be portable between different
+ * DB-column namings, we map the internal name to the real column name here
+ *
+ * @access private
+ * @version 2002/03/02
+ * @author Wolfram Kriesing <wolfram@kriesing.de>
+ * @param string the internal name used
+ * @return string the real name of the column
+ */
+ function _getColName($name)
+ {
+ if (
+ isset($this->conf['fields']) &&
+ isset($this->conf['fields'][$name]['name'])
+ ) {
+ return $this->conf['fields'][$name]['name'];
+ }
+
+ return $name;
+ }
+
+ // }}}
+
+ /*******************************************************************************/
+ /************************ METHODS FROM Tree_Options ****************************/
+ /*******************************************************************************/
+
+ // {{{ setOption()
+
+ /**
+ *
+ * @access public
+ * @author Stig S. Baaken
+ * @param string the option name
+ * @param mixed the value for this option
+ * @param boolean if set to true options are also set
+ * even if no key(s) was/were found in the options property
+ */
+ function setOption($option, $value, $force = false)
+ {
+ if ($option == 'fields') {
+ return false;
+ }
+ // if the value is an array extract the keys
+ // and apply only each value that is set
+ if (is_array($value)) {
+ // so we dont override existing options inside an array
+ // if an option is an array
+ foreach ($value as $key => $aValue) {
+ Tree::setOption(array($option, $key), $aValue);
+ }
+
+ return true;
+ }
+
+ if (is_array($option)) {
+ $mainOption = $option[0];
+ $options = "['".implode("']['",$option)."']";
+ $evalCode = "\$this->conf".$options." = \$value;";
+ } else {
+ $evalCode = "\$this->conf[\$option] = \$value;";
+ $mainOption = $option;
+ }
+
+ if (
+ $force == true
+ || isset($this->conf[$mainOption])
+ ) {
+ eval($evalCode);
+ return true;
+ }
+ return false;
+ }
+
+ // }}}
+ // {{{ setOptions()
+
+ /**
+ * set a number of options which are simply given in an array
+ *
+ * @access public
+ * @param array the values to set
+ * @param boolean if set to true options are also set even if no key(s)
+ * was/were found in the options property
+ */
+ function setOptions($options, $force = false)
+ {
+ if (is_array($options) && count($options)) {
+ foreach ($options as $key => $value) {
+ $this->setOption($key, $value, $force);
+ }
+ }
+ }
+
+ // }}}
+ // {{{ getOption()
+
+ /**
+ *
+ * @access public
+ * @author copied from PEAR: DB/commmon.php
+ * @param boolean true on success
+ */
+ function getOption($option)
+ {
+ if (isset($this->conf[$option])) {
+ return $this->conf[$option];
+ }
+ return false;
+ }
+
+ // }}}
+ // {{{ getOptions()
+
+ /**
+ * returns all the options
+ *
+ * @version 02/05/20
+ * @access public
+ * @author Wolfram Kriesing <wolfram@kriesing.de>
+ * @return string all options as an array
+ */
+ function getOptions()
+ {
+ return $this->conf;
+ }
+
+ // }}}
+}
+
+/**
+ * Tree_Error implements a class for reporting portable database error
+ * messages.
+ *
+ * @package Tree
+ */
+class Tree_Error extends PEAR_Error
+{
+ /**
+ * Tree_Error constructor.
+ *
+ * @param mixed $code Tree error code, or string with error message.
+ * @param integer $mode what 'error mode' to operate in
+ * @param integer $level what error level to use for
+ * $mode & PEAR_ERROR_TRIGGER
+ * @param smixed $debuginfo additional debug info, such as the last query
+ */
+ function Tree_Error($code = TREE_ERROR, $mode = PEAR_ERROR_RETURN,
+ $level = E_USER_NOTICE, $debuginfo = NULL)
+ {
+ if (is_int($code)) {
+ $this->PEAR_Error('Tree Error: ' . Tree::errorMessage($code), $code,
+ $mode, $level, $debuginfo);
+ } else {
+ $this->PEAR_Error("Tree Error: $code", TREE_ERROR, $mode, $level,
+ $debuginfo);
+ }
+ }
+}
+?>
Property changes on: Tree/Tree.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.13.2.2
+1.14
Index: Tree/Admin/Simple.php
===================================================================
Property changes on: Tree/Admin/Simple.php
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.1
Added: svn:eol-style
## -0,0 +1 ##
+native
Index: Tree/Admin/Dynamic/MDBnested.php
===================================================================
--- Tree/Admin/Dynamic/MDBnested.php (.../branches/Tree_0_3_0) (revision 0)
+++ Tree/Admin/Dynamic/MDBnested.php (.../trunk) (revision 321102)
@@ -0,0 +1,35 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+// +----------------------------------------------------------------------+
+// | PHP Version 4 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1997-2005 The PHP Group |
+// +----------------------------------------------------------------------+
+// | This source file is subject to version 3.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/3_0.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: |
+// +----------------------------------------------------------------------+
+//
+// $Id$
+
+require_once 'Tree/Dynamic/MDBnested.php';
+
+/**
+* This class implements methods to work on a tree saved using the nested
+* tree model.
+* explaination: http://research.calacademy.org/taf/proceedings/ballew/index.htm
+*
+* @access public
+* @package Tree
+*/
+class Tree_Dynamic_Admin_MDBnested extends Tree_Dynamic_MDBnested
+{
+
+}
+?>
\ No newline at end of file
Property changes on: Tree/Admin/Dynamic/MDBnested.php
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.1
Added: svn:eol-style
## -0,0 +1 ##
+native
Index: Tree/Admin/Dynamic/DBnested.php
===================================================================
--- Tree/Admin/Dynamic/DBnested.php (.../branches/Tree_0_3_0) (revision 0)
+++ Tree/Admin/Dynamic/DBnested.php (.../trunk) (revision 321102)
@@ -0,0 +1,36 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+// +----------------------------------------------------------------------+
+// | PHP Version 4 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1997-2005 The PHP Group |
+// +----------------------------------------------------------------------+
+// | This source file is subject to version 3.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/3_0.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: |
+// +----------------------------------------------------------------------+
+//
+// $Id$
+
+require_once 'Tree/Dynamic/DBnested.php';
+
+/**
+* This class implements methods to work on a tree saved using the nested
+* tree model.
+* explaination: http://research.calacademy.org/taf/proceedings/ballew/index.htm
+*
+* @access public
+* @package Tree
+*/
+class Tree_Dynamic_Admin_DBnested extends Tree_Dynamic_DBnested
+{
+
+
+}
+?>
\ No newline at end of file
Property changes on: Tree/Admin/Dynamic/DBnested.php
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.1
Added: svn:eol-style
## -0,0 +1 ##
+native
Index: Tree/Memory/MDBsimple.php
===================================================================
--- Tree/Memory/MDBsimple.php (.../branches/Tree_0_3_0) (revision 321102)
+++ Tree/Memory/MDBsimple.php (.../trunk) (revision 321102)
@@ -1,448 +0,0 @@
-<?php
-
-// +----------------------------------------------------------------------+
-// | PHP Version 4 |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2003 The PHP Group |
-// +----------------------------------------------------------------------+
-// | This source file is subject to version 2.02 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: Wolfram Kriesing <wolfram@kriesing.de> |
-// | Lorenzo Alberton <l.alberton@quipo.it> |
-// +----------------------------------------------------------------------+
-
-// $Id$
-require_once 'Tree/OptionsMDB.php';
-require_once 'Tree/Error.php';
-
-/**
-* the MDB interface to the tree class
-*
-* @access public
-* @author Lorenzo Alberton <l.alberton@quipo.it>
-* @package Tree
-*/
-class Tree_Memory_MDBsimple extends Tree_OptionsMDB
-{
- // FIXXME should actually extend Tree_Common, to use the methods provided in there...
- // but we need to connect to the db here, so we extend optionsMDB for now, may be use
- // "aggregate" function to fix that
-
- /**
- * @access public
- * @var array saves the options passed to the constructor. Valid options:
- * - order: which column to order by when reading the data from the DB,
- * this sorts the data even inside every level
- * - whereAddOn: add on for the where clause, this string is simply
- * added behind the WHERE in the select, so you better make
- * sure its correct SQL :-), i.e. 'uid=3'.
- * This is needed i.e. when you are saving many trees for different
- * user in one table where each entry has a uid (user id)
- * - columnNameMaps: the column-name maps are used for the "as" in the select
- * queries so you can use any column name in the table and "map"
- * it to the name that shall be used in the internal array,
- * that is built, see the examples (in comments)
- * - columnNameMaps: array for id/parentId/prevId/name table column names
- */
- var $options = array('order' => '',
- 'whereAddOn' => '',
- 'table' => '',
- 'columnNameMaps' => array(
- /* 'id' => 'tree_id', // use "tree_id" as "id"
- 'parentId' => 'parent_id',
- 'prevId' => 'previous_id',
- 'name' => 'nodeName'
- */
- ),
- );
-
- /**
- * @access public
- * @var string the table where to read the tree data from
- * can also be set using the DSN in the constructor
- */
- var $table;
-
- /**
- * @access private
- * @var object $dbh the handle to the DB-object
- */
- // var $dbh;
-
- // {{{ Tree_Memory_MDBsimple()
-
- /**
- * set up this object
- *
- * @access public
- * @param string $dsn this is a DSN of the for that PEAR::DB uses it
- * only that additionally you can add parameters like ...?table=test_table
- * to define the table it shall work on
- * @param array $options additional options you can set
- */
- function Tree_Memory_MDBsimple($dsn, $options = array())
- {
- $this->Tree_OptionsMDB($dsn, $options); // instanciate DB
- if (is_string($options)) {
- // just to be backward compatible, or to make the second paramter shorter
- $this->setOption('order', $options);
- }
-
- $this->table = $this->getOption('table');
- }
-
- // }}}
- // {{{ setup()
-
- /**
- * retrieve all the navigation data from the db and call build to build the
- * tree in the array data and structure
- *
- * @access public
- * @return boolean true on success
- */
- function setup()
- {
- // TODO sort by prevId (parentId, prevId $addQuery) too if it exists in the table,
- // or the root might be wrong, since the prevId of the root should be 0
-
- $whereAddOn = '';
- if ($this->options['whereAddOn']) {
- $whereAddOn = 'WHERE ' . $this->getOption('whereAddOn');
- }
-
- $orderBy = '';
- if ($this->options['order']) {
- $orderBy = ',' . $this->options['order'];
- }
-
- $map = $this->getOption('columnNameMaps');
- if (isset($map['parentId'])) {
- $orderBy = $map['parentId'] . $orderBy;
- } else {
- $orderBy = 'parentId' . $orderBy;
- }
- // build the query this way, that the root, which has no parent (parentId=0)
- // and no previous (prevId=0) is in first place (in case prevId is given)
- $query = sprintf("SELECT * FROM %s %s ORDER BY %s",
- $this->table,
- $whereAddOn,
- $orderBy); //,prevId !!!!
- if (MDB::isError($res = $this->dbh->getAll($query))) {
- // FIXXME remove print use debug mode instead
- printf("ERROR - Tree::setup - %s - %s<br />", MDB::errorMessage($res), $query);
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- // if the db-column names need to be mapped to different names
- // FIXXME somehow we should be able to do this in the query, but I dont know
- // how to select only those columns, use "as" on them and select the rest,
- //without getting those columns again :-(
- if ($map) {
- foreach ($res as $id => $aResult) { // map each result
- foreach ($map as $key => $columnName) {
- $res[$id][$key] = $res[$id][$columnName];
- unset($res[$id][$columnName]);
- }
- }
- }
-
- return $res;
- }
-
- // }}}
- // {{{ add()
-
- /**
- * adds _one_ new element in the tree under the given parent
- * the values' keys given have to match the db-columns, because the
- * value gets inserted in the db directly
- * to add an entire node containing children and so on see 'addNode()'
- *
- * to be compatible with the MDBnested, u can also give the parent and previd
- * as the second and third parameter
- *
- * @see addNode
- * @access public
- * @param array $newValues this array contains the values that shall be inserted in the db-table
- * the key for each element is the name of the column
- * @return mixed either boolean false on failure or the id of the inserted row
- */
- function add($newValues, $parentId = 0)
- {
- // FIXXME use $this->dbh->tableInfo to check which columns exist
- // so only data for which a column exist is inserted
- if ($parentId) {
- $newValues['parentId'] = $parentId;
- }
- $newData = array();
- foreach ($newValues as $key => $value) {
- // quote the values, as needed for the insert
- $newData[$this->_getColName($key)] = $this->_quote($value);
- }
- // use sequences to create a new id in the db-table
- $nextId = $this->dbh->nextId($this->table);
- $query = sprintf("INSERT INTO %s (%s,%s) VALUES (%s,%s)",
- $this->table ,
- $this->_getColName('id'),
- implode(',', array_keys($newData)) ,
- $nextId,
- implode(',', $newData));
- if (MDB::isError($res = $this->dbh->query($query))) {
- // TODO raise PEAR error
- printf("ERROR - Tree::add - %s - %s<br />", MDB::errorMessage($res), $query);
- return false;
- }
-
- return $nextId;
- }
-
- // }}}
- // {{{ remove()
-
- /**
- * removes the given node
- *
- * @access public
- * @param mixed $id the id of the node to be removed, or an array of id's to be removed
- * @return boolean true on success
- */
- function remove($id)
- {
- // if the one to remove has children, get their id's to remove them too
- if ($this->hasChildren($id)) {
- $id = $this->walk(array('_remove', $this), $id, 'array');
- }
- $idColumnName = 'id';
- $map = $this->getOption('columnNameMaps');
- if (isset($map['id'])) { // if there are maps given
- $idColumnName = $map['id'];
- }
-
- $whereClause = "WHERE $idColumnName=$id";
- if (is_array($id)) {
- $whereClause = "WHERE $idColumnName in (" . implode(',', $id) . ')';
- }
-
- $query = "DELETE FROM {$this->table} $whereClause";
- // print('<br />'.$query);
- if (MDB::isError($res = $this->dbh->query($query))) {
- // TODO raise PEAR error
- printf("ERROR - Tree::remove - %s - %s<br>", MDB::errormessage($res), $query);
- return false;
- }
- // TODO if remove succeeded set prevId of the following element properly
- return true;
- }
-
- // }}}
- // {{{ move()
-
- /**
- * move an entry under a given parent or behind a given entry
- *
- * @version 2001/10/10
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param integer $idToMove the id of the element that shall be moved
- * @param integer $newParentId the id of the element which will be the new parent
- * @param integer $newPrevId if prevId is given the element with the id idToMove
- * shall be moved _behind_ the element with id=prevId
- * if it is 0 it will be put at the beginning
- * if no prevId is in the DB it can be 0 too and won't bother
- * since it is not written in the DB anyway
- * @return boolean true for success
- */
- function move($idToMove, $newParentId, $newPrevId = 0)
- {
- $idColumnName = 'id';
- $parentIdColumnName = 'parentId';
- $map = $this->getOption('columnNameMaps');
- if (isset($map['id'])) {
- $idColumnName = $map['id'];
- }
- if (isset($map['parentId'])) {
- $parentIdColumnName = $map['parentId'];
- }
- // FIXXME todo: previous stuff
- // set the parent in the DB
- $query = "UPDATE $this->table SET $parentIdColumnName=$newParentId WHERE $idColumnName=$idToMove";
- // print($query);
- if (MDB::isError($res = $this->dbh->query($query))) {
- // TODO raise PEAR error
- printf("ERROR - Tree::move - %s - %s<br>", MDB::errorMessage($res), $query);
- return false;
- }
- // FIXXME update the prevId's of the elements where the element was moved away from and moved in
- return true;
- }
-
- // }}}
- // {{{ update()
-
- /**
- * update an element in the DB
- *
- * @version 2002/01/17
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param array $newData all the new data, the key 'id' is used to
- build the 'WHERE id=' clause and all the other
- * elements are the data to fill in the DB
- * @return boolean true for success
- */
- function update($id, $newData)
- {
- // FIXXME check $this->dbh->tableInfo to see if all the columns that shall be updated
- // really exist, this will also extract nextId etc. if given before writing it in the DB
- // in case they dont exist in the DB
- $setData = array();
- foreach ($newData as $key => $value) { // quote the values, as needed for the insert
- $setData[] = $this->_getColName($key) . '=' . $this->_quote($value);
- }
-
- $query = sprintf('UPDATE %s SET %s WHERE %s=%s',
- $this->table,
- implode(',', $setData),
- $this->_getColName('id'),
- $id
- );
- if (MDB::isError($res = $this->dbh->query($query))) {
- // FIXXME raise PEAR error
- printf("ERROR - Tree::update - %s - %s<br>", MDB::errormessage($res), $query);
- return false;
- }
-
- return true;
- }
-
- // }}}
- // {{{ _throwError()
-
- /**
- *
- * @access private
- * @version 2002/03/02
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- */
- function _throwError($msg, $line, $mode = null)
- {
- return new Tree_Error($msg, $line, __FILE__, $mode, $this->dbh->last_query);
- }
-
- // }}}
- // {{{ _prepareResults()
-
- /**
- * prepare multiple results
- *
- * @see _prepareResult
- * @access private
- * @version 2002/03/03
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- */
- function _prepareResults($results)
- {
- $newResults = array();
- foreach ($results as $aResult) {
- $newResults[] = $this->_prepareResult($aResult);
- }
- return $newResults;
- }
-
- // }}}
- // {{{ _prepareResult()
-
- /**
- * map back the index names to get what is expected
- *
- * @access private
- * @version 2002/03/03
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- */
- function _prepareResult($result)
- {
- $map = $this->getOption('columnNameMaps');
-
- if ($map) {
- foreach ($map as $key => $columnName) {
- $result[$key] = $result[$columnName];
- unset($result[$columnName]);
- }
- }
- return $result;
- }
-
- // }}}
- // {{{ _getColName()
-
- /**
- * this method retreives the real column name, as used in the DB
- * since the internal names are fixed, to be portable between different
- * DB-column namings, we map the internal name to the real column name here
- *
- * @access private
- * @version 2002/03/02
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- */
- function _getColName($internalName)
- {
- if ($map = $this->getOption('columnNameMaps')) {
- if (isset($map[$internalName])) {
- return $map[$internalName];
- }
- }
- return $internalName;
- }
-
- // }}}
- // {{{ _quoteArray()
-
- /**
- * quotes all the data in this array
- *
- * @param array $data Array to quote
- */
- function _quoteArray($data)
- {
- foreach ($data as $key => $val) {
- $data[$key] = $this->_quote($val);
- }
- return $data;
- }
-
- // }}}
- // {{{ _quote()
-
- /**
- * quotes all the data in this var (can be any type except object)
- * @param mixed $data data to quote
- */
- function _quote($data)
- {
- switch(gettype($data)) {
- case 'array':
- return $this->_quoteArray($data);
- break;
- case 'boolean':
- return $this->dbh->getBooleanValue($data);
- break;
- case 'double':
- return $this->dbh->getFloatValue($data);
- break;
- case 'integer':
- return $this->dbh->getIntegerValue($data);
- break;
- case 'string': //if 'string' or 'unknown', quote as text
- default:
- return $this->dbh->getTextValue($data);
- }
- }
-
- // }}}
-}
\ No newline at end of file
Index: Tree/Memory/MDB2simple.php
===================================================================
--- Tree/Memory/MDB2simple.php (.../branches/Tree_0_3_0) (revision 321102)
+++ Tree/Memory/MDB2simple.php (.../trunk) (revision 321102)
@@ -1,443 +0,0 @@
-<?php
-
-// +----------------------------------------------------------------------+
-// | PHP Version 4 |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2003 The PHP Group |
-// +----------------------------------------------------------------------+
-// | This source file is subject to version 2.02 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: Wolfram Kriesing <wolfram@kriesing.de> |
-// | Lorenzo Alberton <l.alberton@quipo.it> |
-// +----------------------------------------------------------------------+
-
-// $Id$
-require_once 'Tree/OptionsMDB2.php';
-
-/**
-* the MDB2 interface to the tree class
-*
-* @access public
-* @author Lorenzo Alberton <l.alberton@quipo.it>
-* @package Tree
-*/
-class Tree_Memory_MDB2simple extends Tree_OptionsMDB2
-{
- // FIXXME should actually extend Tree_Common, to use the methods provided in there...
- // but we need to connect to the db here, so we extend optionsMDB2 for now, may be use
- // "aggregate" function to fix that
-
- /**
- * @access public
- * @var array saves the options passed to the constructor. Valid options:
- * - order: which column to order by when reading the data from the DB,
- * this sorts the data even inside every level
- * - whereAddOn: add on for the where clause, this string is simply
- * added behind the WHERE in the select, so you better make
- * sure its correct SQL :-), i.e. 'uid=3'.
- * This is needed i.e. when you are saving many trees for different
- * user in one table where each entry has a uid (user id)
- * - columnNameMaps: the column-name maps are used for the "as" in the select
- * queries so you can use any column name in the table and "map"
- * it to the name that shall be used in the internal array,
- * that is built, see the examples (in comments)
- * - columnNameMaps: array for id/parentId/prevId/name table column names
- */
- var $options = array('order' => '',
- 'whereAddOn' => '',
- 'table' => '',
- 'columnNameMaps' => array(
- /* 'id' => 'tree_id', // use "tree_id" as "id"
- 'parentId' => 'parent_id',
- 'prevId' => 'previous_id',
- 'name' => 'nodeName'
- */
- ),
- );
-
- /**
- * @access public
- * @var string the table where to read the tree data from
- * can also be set using the DSN in the constructor
- */
- var $table;
-
- /**
- * @access private
- * @var object $dbh the handle to the DB-object
- */
- // var $dbh;
-
- // {{{ Tree_Memory_MDB2simple()
-
- /**
- * set up this object
- *
- * @access public
- * @param string $dsn this is a DSN of the for that PEAR::DB uses it
- * only that additionally you can add parameters like ...?table=test_table
- * to define the table it shall work on
- * @param array $options additional options you can set
- */
- function Tree_Memory_MDB2simple($dsn, $options = array())
- {
- $this->Tree_OptionsMDB2($dsn, $options); // instanciate DB
- if (is_string($options)) {
- // just to be backward compatible, or to make the second paramter shorter
- $this->setOption('order', $options);
- }
-
- $this->table = $this->getOption('table');
- }
-
- // }}}
- // {{{ setup()
-
- /**
- * retrieve all the navigation data from the db and call build to build the
- * tree in the array data and structure
- *
- * @access public
- * @return boolean true on success
- */
- function setup()
- {
- // TODO sort by prevId (parentId, prevId $addQuery) too if it exists in the table,
- // or the root might be wrong, since the prevId of the root should be 0
-
- $whereAddOn = '';
- if ($this->options['whereAddOn']) {
- $whereAddOn = 'WHERE ' . $this->getOption('whereAddOn');
- }
-
- $orderBy = '';
- if ($this->options['order']) {
- $orderBy = ',' . $this->options['order'];
- }
-
- $map = $this->getOption('columnNameMaps');
- if (isset($map['parentId'])) {
- $orderBy = $map['parentId'] . $orderBy;
- } else {
- $orderBy = 'parentId' . $orderBy;
- }
- // build the query this way, that the root, which has no parent (parentId=0)
- // and no previous (prevId=0) is in first place (in case prevId is given)
- $query = sprintf("SELECT * FROM %s %s ORDER BY %s",
- $this->table,
- $whereAddOn,
- $orderBy); //,prevId !!!!
- if (MDB2::isError($res = $this->dbh->queryAll($query))) {
- // FIXXME remove print use debug mode instead
- printf("ERROR - Tree::setup - %s - %s<br />", MDB2::errorMessage($res), $query);
- return Tree::raiseError('TREE_ERROR_RAISE_ERROR', $res->getMessage());
- }
-
- // Account for the fact the by default MDB2 lower cases field names
- // But only if people are not doing the mapping them self
- if (!isset($map['parentId']) || $map['parentId'] != 'parentid') {
- foreach ($res as $index => $value) {
- $res[$index]['parentId'] = $res[$index]['parentid'];
- unset($res[$index]['parentid']);
- }
- }
-
- // if the db-column names need to be mapped to different names
- // FIXXME somehow we should be able to do this in the query, but I dont know
- // how to select only those columns, use "as" on them and select the rest,
- //without getting those columns again :-(
- if ($map) {
- foreach ($res as $id => $aResult) { // map each result
- foreach ($map as $key => $columnName) {
- $res[$id][$key] = $res[$id][$columnName];
- unset($res[$id][$columnName]);
- }
- }
- }
-
- return $res;
- }
-
- // }}}
- // {{{ add()
-
- /**
- * adds _one_ new element in the tree under the given parent
- * the values' keys given have to match the db-columns, because the
- * value gets inserted in the db directly
- * to add an entire node containing children and so on see 'addNode()'
- *
- * to be compatible with the MDB2nested, u can also give the parent and previd
- * as the second and third parameter
- *
- * @see addNode
- * @access public
- * @param array $newValues this array contains the values that shall be inserted in the db-table
- * the key for each element is the name of the column
- * @return mixed either boolean false on failure or the id of the inserted row
- */
- function add($newValues, $parentId = 0)
- {
- // FIXXME use $this->dbh->tableInfo to check which columns exist
- // so only data for which a column exist is inserted
- if ($parentId) {
- $newValues['parentId'] = $parentId;
- }
- $newData = array();
- foreach ($newValues as $key => $value) {
- // quote the values, as needed for the insert
- $newData[$this->_getColName($key)] = $this->_quote($value);
- }
- // use sequences to create a new id in the db-table
- $nextId = $this->dbh->nextId($this->table);
- $query = sprintf("INSERT INTO %s (%s,%s) VALUES (%s,%s)",
- $this->table ,
- $this->_getColName('id'),
- implode(',', array_keys($newData)) ,
- $nextId,
- implode(',', $newData));
- if (MDB2::isError($res = $this->dbh->exec($query))) {
- // TODO raise PEAR error
- printf("ERROR - Tree::add - %s - %s<br />", MDB2::errorMessage($res), $query);
- return false;
- }
-
- return $nextId;
- }
-
- // }}}
- // {{{ remove()
-
- /**
- * removes the given node
- *
- * @access public
- * @param mixed $id the id of the node to be removed, or an array of id's to be removed
- * @return boolean true on success
- */
- function remove($id)
- {
- // if the one to remove has children, get their id's to remove them too
- if ($this->hasChildren($id)) {
- $id = $this->walk(array('_remove', $this), $id, 'array');
- }
- $idColumnName = 'id';
- $map = $this->getOption('columnNameMaps');
- if (isset($map['id'])) { // if there are maps given
- $idColumnName = $map['id'];
- }
-
- $whereClause = "WHERE $idColumnName=$id";
- if (is_array($id)) {
- $whereClause = "WHERE $idColumnName in (" . implode(',', $id) . ')';
- }
-
- $query = "DELETE FROM {$this->table} $whereClause";
- // print('<br />'.$query);
- if (MDB2::isError($res = $this->dbh->exec($query))) {
- // TODO raise PEAR error
- printf("ERROR - Tree::remove - %s - %s<br>", MDB2::errormessage($res), $query);
- return false;
- }
- // TODO if remove succeeded set prevId of the following element properly
- return true;
- }
-
- // }}}
- // {{{ move()
-
- /**
- * move an entry under a given parent or behind a given entry
- *
- * @version 2001/10/10
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param integer $idToMove the id of the element that shall be moved
- * @param integer $newParentId the id of the element which will be the new parent
- * @param integer $newPrevId if prevId is given the element with the id idToMove
- * shall be moved _behind_ the element with id=prevId
- * if it is 0 it will be put at the beginning
- * if no prevId is in the DB it can be 0 too and won't bother
- * since it is not written in the DB anyway
- * @return boolean true for success
- */
- function move($idToMove, $newParentId, $newPrevId = 0)
- {
- $idColumnName = 'id';
- $parentIdColumnName = 'parentId';
- $map = $this->getOption('columnNameMaps');
- if (isset($map['id'])) {
- $idColumnName = $map['id'];
- }
- if (isset($map['parentId'])) {
- $parentIdColumnName = $map['parentId'];
- }
- // FIXXME todo: previous stuff
- // set the parent in the DB
- $query = "UPDATE $this->table SET $parentIdColumnName=$newParentId WHERE $idColumnName=$idToMove";
- // print($query);
- if (MDB2::isError($res = $this->dbh->exec($query))) {
- // TODO raise PEAR error
- printf("ERROR - Tree::move - %s - %s<br>", MDB2::errorMessage($res), $query);
- return false;
- }
- // FIXXME update the prevId's of the elements where the element was moved away from and moved in
- return true;
- }
-
- // }}}
- // {{{ update()
-
- /**
- * update an element in the DB
- *
- * @version 2002/01/17
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param array $newData all the new data, the key 'id' is used to
- build the 'WHERE id=' clause and all the other
- * elements are the data to fill in the DB
- * @return boolean true for success
- */
- function update($id, $newData)
- {
- // FIXXME check $this->dbh->tableInfo to see if all the columns that shall be updated
- // really exist, this will also extract nextId etc. if given before writing it in the DB
- // in case they dont exist in the DB
- $setData = array();
- foreach ($newData as $key => $value) { // quote the values, as needed for the insert
- $setData[] = $this->_getColName($key) . '=' . $this->_quote($value);
- }
-
- $query = sprintf('UPDATE %s SET %s WHERE %s=%s',
- $this->table,
- implode(',', $setData),
- $this->_getColName('id'),
- $id
- );
- if (MDB2::isError($res = $this->dbh->exec($query))) {
- // FIXXME raise PEAR error
- printf("ERROR - Tree::update - %s - %s<br>", MDB2::errormessage($res), $query);
- return false;
- }
-
- return true;
- }
-
- // }}}
- // {{{ _prepareResults()
-
- /**
- * prepare multiple results
- *
- * @see _prepareResult
- * @access private
- * @version 2002/03/03
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- */
- function _prepareResults($results)
- {
- $newResults = array();
- foreach ($results as $aResult) {
- $newResults[] = $this->_prepareResult($aResult);
- }
- return $newResults;
- }
-
- // }}}
- // {{{ _prepareResult()
-
- /**
- * map back the index names to get what is expected
- *
- * @access private
- * @version 2002/03/03
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- */
- function _prepareResult($result)
- {
- $map = $this->getOption('columnNameMaps');
-
- if ($map) {
- foreach ($map as $key => $columnName) {
- $result[$key] = $result[$columnName];
- unset($result[$columnName]);
- }
- }
- return $result;
- }
-
- // }}}
- // {{{ _getColName()
-
- /**
- * this method retreives the real column name, as used in the DB
- * since the internal names are fixed, to be portable between different
- * DB-column namings, we map the internal name to the real column name here
- *
- * @access private
- * @version 2002/03/02
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- */
- function _getColName($internalName)
- {
- if ($map = $this->getOption('columnNameMaps')) {
- if (isset($map[$internalName])) {
- return $map[$internalName];
- }
- }
- return $internalName;
- }
-
- // }}}
- // {{{ _quoteArray()
-
- /**
- * quotes all the data in this array
- *
- * @param array $data Array to quote
- */
- function _quoteArray($data)
- {
- foreach ($data as $key => $val) {
- $data[$key] = $this->_quote($val);
- }
- return $data;
- }
-
- // }}}
- // {{{ _quote()
-
- /**
- * quotes all the data in this var (can be any type except object)
- * @param mixed $data data to quote
- */
- function _quote($data)
- {
- switch(gettype($data)) {
- case 'array':
- return $this->_quoteArray($data);
- break;
- case 'boolean':
- return $this->dbh->quote($data);
- break;
- case 'double':
- return $this->dbh->quote($data);
- break;
- case 'integer':
- return $this->dbh->quote($data);
- break;
- case 'string': //if 'string' or 'unknown', quote as text
- default:
- return $this->dbh->quote($data);
- }
- }
-
- // }}}
-}
\ No newline at end of file
Index: Tree/Memory/DBsimple.php
===================================================================
--- Tree/Memory/DBsimple.php (.../branches/Tree_0_3_0) (revision 321102)
+++ Tree/Memory/DBsimple.php (.../trunk) (revision 321102)
@@ -1,409 +0,0 @@
-<?php
-// +----------------------------------------------------------------------+
-// | PHP Version 4 |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2003 The PHP Group |
-// +----------------------------------------------------------------------+
-// | This source file is subject to version 2.02 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: Wolfram Kriesing <wolfram@kriesing.de> |
-// +----------------------------------------------------------------------+
-
-// $Id$
-require_once 'Tree/OptionsDB.php';
-require_once 'Tree/Error.php';
-
-/**
- * the DB interface to the tree class
- *
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @version 2001/06/27
- * @package Tree
- */
-class Tree_Memory_DBsimple extends Tree_OptionsDB
-{
- // FIXXME should actually extend Tree_Common, to use the methods provided in there...
- // but we need to connect to the db here, so we extend optionsMDB for now, may be use
- // "aggregate" function to fix that
-
- /**
- * @access public
- * @var array saves the options passed to the constructor. Valid options:
- * - order: which column to order by when reading the data from the DB,
- * this sorts the data even inside every level
- * - whereAddOn: add on for the where clause, this string is simply
- * added behind the WHERE in the select, so you better make
- * sure its correct SQL :-), i.e. 'uid=3'.
- * This is needed i.e. when you are saving many trees for different
- * user in one table where each entry has a uid (user id)
- * - columnNameMaps: the column-name maps are used for the "as" in the select
- * queries so you can use any column name in the table and "map"
- * it to the name that shall be used in the internal array,
- * that is built, see the examples (in comments)
- * - columnNameMaps: array for id/parentId/prevId/name table column names
- */
- var $options = array('order' => '',
- 'whereAddOn' => '',
- 'table' => '',
- 'columnNameMaps' => array(
- /* 'id' => 'tree_id', // use "tree_id" as "id"
- 'parentId' => 'parent_id',
- 'prevId' => 'previous_id',
- 'name' => 'nodeName'
- */
- ),
- );
-
- /**
- *
- * @access public
- * @var string the table where to read the tree data from
- * can also be set using the DSN in the constructor
- */
- var $table;
-
- /**
- *
- * @access private
- * @var object $dbh the handle to the DB-object
- */
- // var $dbh;
-
- // {{{ Tree_Memory_DBsimple()
-
- /**
- * set up this object
- *
- * @version 2001/06/27
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param string $dsn this is a DSN of the for that PEAR::DB uses it
- * only that additionally you can add parameters like ...?table=test_table
- * to define the table it shall work on
- * @param array $options additional options you can set
- */
- function Tree_Memory_DBsimple($dsn, $options = array())
- {
- $this->Tree_OptionsDB($dsn, $options); // instanciate DB
- if (is_string($options)) {
- // just to be backward compatible, or to make the second paramter shorter
- $this->setOption('order', $options);
- }
-
- $this->table = $this->getOption('table');
- }
-
- // }}}
- // {{{ setup()
-
- /**
- * retreive all the navigation data from the db and call build to build the
- * tree in the array data and structure
- *
- * @version 2001/11/20
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @return boolean true on success
- */
- function setup()
- {
- // TODO sort by prevId (parentId,prevId $addQuery) too if it exists in the table, or the root might be wrong
- // TODO since the prevId of the root should be 0
-
- $whereAddOn = '';
- if ($this->options['whereAddOn']) {
- $whereAddOn = 'WHERE ' . $this->getOption('whereAddOn');
- }
-
- $orderBy = '';
- if ($this->options['order']) {
- $orderBy = ',' . $this->options['order'];
- }
-
- $map = $this->getOption('columnNameMaps');
- if (isset($map['parentId'])) {
- $orderBy = $map['parentId'] . $orderBy;
- } else {
- $orderBy = 'parentId' . $orderBy;
- }
- // build the query this way, that the root, which has no parent (parentId=0)
- // and no previous (prevId=0) is in first place (in case prevId is given)
- $query = sprintf("SELECT * FROM %s %s ORDER BY %s",
- $this->table,
- $whereAddOn,
- $orderBy); //,prevId !!!!
- if (DB::isError($res = $this->dbh->getAll($query))) {
- // FIXXME remove print use debug mode instead
- printf("ERROR - Tree::setup - %s - %s<br>", DB::errormessage($res), $query);
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- // if the db-column names need to be mapped to different names
- // FIXXME somehow we should be able to do this in the query, but i dont know how to select
- // only those columns, use "as" on them and select the rest, without getting those columns again :-(
- if ($map) {
- foreach($res as $id => $aResult) { // map each result
- foreach($map as $key => $columnName) {
- $res[$id][$key] = $res[$id][$columnName];
- unset($res[$id][$columnName]);
- }
- }
- }
-
- return $res;
- }
-
- // }}}
- // {{{ add()
-
- /**
- * adds _one_ new element in the tree under the given parent
- * the values' keys given have to match the db-columns, because the
- * value gets inserted in the db directly
- * to add an entire node containing children and so on see 'addNode()'
- *
- * to ba compatible, to the DBnested u can also give the parent and previd as the second and third parameter
- *
- * @see addNode
- * @version 2001/10/09
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param array $newValues this array contains the values that shall be inserted in the db-table
- * the key for each element is the name of the column
- * @return mixed either boolean false on failure or the id of the inserted row
- */
- function add($newValues, $parentId = 0)
- {
- // FIXXME use $this->dbh->tableInfo to check which columns exist
- // so only data for which a column exist is inserted
- if ($parentId) {
- $newValues['parentId'] = $parentId;
- }
- $newData = array();
- foreach($newValues as $key => $value) { // quote the values, as needed for the insert
- $newData[$this->_getColName($key)] = $this->dbh->quote($value);
- }
- // use sequences to create a new id in the db-table
- $nextId = $this->dbh->nextId($this->table);
- $query = sprintf("INSERT INTO %s (%s,%s) VALUES (%s,%s)",
- $this->table ,
- $this->_getColName('id'),
- implode(',', array_keys($newData)) ,
- $nextId,
- implode(',', $newData));
- if (DB::isError($res = $this->dbh->query($query))) {
- // TODO raise PEAR error
- printf("ERROR - Tree::add - %s - %s<br>", DB::errormessage($res), $query);
- return false;
- }
-
- return $nextId;
- }
-
- // }}}
- // {{{ remove()
-
- /**
- * removes the given node
- *
- * @version 2001/10/09
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param mixed $id the id of the node to be removed, or an array of id's to be removed
- * @return boolean true on success
- */
- function remove($id)
- {
- // if the one to remove has children, get their id's to remove them too
- if ($this->hasChildren($id)) {
- $id = $this->walk(array('_remove', $this), $id, 'array');
- }
- $idColumnName = 'id';
- $map = $this->getOption('columnNameMaps');
- if (isset($map['id'])) { // if there are maps given
- $idColumnName = $map['id'];
- }
-
- $whereClause = "WHERE $idColumnName=$id";
- if (is_array($id)) {
- $whereClause = "WHERE $idColumnName in (" . implode(',', $id) . ')';
- }
-
- $query = "DELETE FROM {$this->table} $whereClause";
- // print("<br>".$query);
- if (DB::isError($res = $this->dbh->query($query))) {
- // TODO raise PEAR error
- printf("ERROR - Tree::remove - %s - %s<br>", DB::errormessage($res), $query);
- return false;
- }
- // TODO if remove succeeded set prevId of the following element properly
- return true;
- }
-
- // }}}
- // {{{ move()
-
- /**
- * move an entry under a given parent or behind a given entry
- *
- * @version 2001/10/10
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param integer $idToMove the id of the element that shall be moved
- * @param integer $newParentId the id of the element which will be the new parent
- * @param integer $newPrevId if prevId is given the element with the id idToMove
- * shall be moved _behind_ the element with id=prevId
- * if it is 0 it will be put at the beginning
- * if no prevId is in the DB it can be 0 too and won't bother
- * since it is not written in the DB anyway
- * @return boolean true for success
- */
- function move($idToMove, $newParentId, $newPrevId = 0)
- {
- $idColumnName = 'id';
- $parentIdColumnName = 'parentId';
- $map = $this->getOption('columnNameMaps');
- if (isset($map['id'])) {
- $idColumnName = $map['id'];
- }
- if (isset($map['parentId'])) {
- $parentIdColumnName = $map['parentId'];
- }
- // FIXXME todo: previous stuff
- // set the parent in the DB
- $query = "UPDATE $this->table SET $parentIdColumnName=$newParentId WHERE $idColumnName=$idToMove";
- // print($query);
- if (DB::isError($res = $this->dbh->query($query))) {
- // TODO raise PEAR error
- printf("ERROR - Tree::move - %s - %s<br>", DB::errormessage($res), $query);
- return false;
- }
- // FIXXME update the prevId's of the elements where the element was moved away from and moved in
- return true;
- }
-
- // }}}
- // {{{ update()
-
- /**
- * update an element in the DB
- *
- * @version 2002/01/17
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param array $newData all the new data, the key 'id' is used to
- * build the 'WHERE id=' clause and all the other
- * elements are the data to fill in the DB
- * @return boolean true for success
- */
- function update($id, $newData)
- {
- // FIXXME check $this->dbh->tableInfo to see if all the columns that shall be updated
- // really exist, this will also extract nextId etc. if given before writing it in the DB
- // in case they dont exist in the DB
- $setData = array();
- foreach($newData as $key => $value) { // quote the values, as needed for the insert
- $setData[] = $this->_getColName($key) . '=' . $this->dbh->quote($value);
- }
-
- $query = sprintf('UPDATE %s SET %s WHERE %s=%s',
- $this->table,
- implode(',', $setData),
- $this->_getColName('id'),
- $id
- );
- if (DB::isError($res = $this->dbh->query($query))) {
- // FIXXME raise PEAR error
- printf("ERROR - Tree::update - %s - %s<br>", DB::errormessage($res), $query);
- return false;
- }
-
- return true;
- }
-
- // }}}
- // {{{ _throwError()
-
- /**
- *
- * @access private
- * @version 2002/03/02
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- */
- function _throwError($msg, $line, $mode = null)
- {
- return new Tree_Error($msg, $line, __FILE__, $mode, $this->db->last_query);
- }
-
- // }}}
- // {{{ _prepareResults()
-
- /**
- * prepare multiple results
- *
- * @see _prepareResult
- * @access private
- * @version 2002/03/03
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- */
- function _prepareResults($results)
- {
- $newResults = array();
- foreach($results as $aResult)
- $newResults[] = $this->_prepareResult($aResult);
- return $newResults;
- }
-
- // }}}
- // {{{ _prepareResult()
-
- /**
- * map back the index names to get what is expected
- *
- * @access private
- * @version 2002/03/03
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- */
- function _prepareResult($result)
- {
- $map = $this->getOption('columnNameMaps');
-
- if ($map) {
- foreach($map as $key => $columnName) {
- $result[$key] = $result[$columnName];
- unset($result[$columnName]);
- }
- }
- return $result;
- }
-
- // }}}
- // {{{ _getColName()
-
- /**
- * this method retreives the real column name, as used in the DB
- * since the internal names are fixed, to be portable between different
- * DB-column namings, we map the internal name to the real column name here
- *
- * @access private
- * @version 2002/03/02
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- */
- function _getColName($internalName)
- {
- if ($map = $this->getOption('columnNameMaps')) {
- if (isset($map[$internalName])) {
- return $map[$internalName];
- }
- }
- return $internalName;
- }
-
- // }}}
-}
\ No newline at end of file
Index: Tree/Memory/MDBnested.php
===================================================================
--- Tree/Memory/MDBnested.php (.../branches/Tree_0_3_0) (revision 321102)
+++ Tree/Memory/MDBnested.php (.../trunk) (revision 321102)
@@ -1,76 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4: */
-// +----------------------------------------------------------------------+
-// | PHP Version 4 |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2003 The PHP Group |
-// +----------------------------------------------------------------------+
-// | This source file is subject to version 2.02 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: |
-// +----------------------------------------------------------------------+
-//
-// $Id$
-
-require_once 'Tree/Dynamic/MDBnested.php';
-
-/**
-*
-*
-* @access public
-* @author
-* @package Tree
-*/
-class Tree_Memory_MDBnested extends Tree_Dynamic_MDBnested
-{
-
- /**
- * retreive all the data from the db and prepare the data so the structure
- * can be built in the parent class
- *
- * @version 2002/04/20
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param array the result of a query which retreives (all)
- * the tree data from a DB
- * @return array the result
- */
- function setup($res = null)
- {
- if ($res == null) {
- //
- $whereAddOn = '';
- if ($this->options['whereAddOn']) {
- $whereAddOn = 'WHERE '.$this->getOption('whereAddOn');
- }
-
- //
- $orderBy = 'left';
- if ($order=$this->getOption('order')) {
- $orderBy = $order;
- }
-
- // build the query this way, that the root, which has no parent
- // (parentId=0) is first
- $query = sprintf('SELECT * FROM %s %s ORDER BY %s',
- $this->table,
- $whereAddOn,
- // sort by the left-column, so we have the data
- //sorted as it is supposed to be :-)
- $this->_getColName($orderBy)
- );
- if (MDB::isError($res = $this->dbh->getAll($query))) {
- return $this->_throwError($res->getMessage(), __LINE__);
- }
- }
-
- return $this->_prepareResults($res);
- }
-
-}
\ No newline at end of file
Index: Tree/Memory/MDB2nested.php
===================================================================
--- Tree/Memory/MDB2nested.php (.../branches/Tree_0_3_0) (revision 321102)
+++ Tree/Memory/MDB2nested.php (.../trunk) (revision 321102)
@@ -1,76 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4: */
-// +----------------------------------------------------------------------+
-// | PHP Version 4 |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2003 The PHP Group |
-// +----------------------------------------------------------------------+
-// | This source file is subject to version 2.02 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: |
-// +----------------------------------------------------------------------+
-//
-// $Id$
-
-require_once 'Tree/Dynamic/MDB2nested.php';
-
-/**
-*
-*
-* @access public
-* @author
-* @package Tree
-*/
-class Tree_Memory_MDB2nested extends Tree_Dynamic_MDB2nested
-{
-
- /**
- * retreive all the data from the db and prepare the data so the structure
- * can be built in the parent class
- *
- * @version 2002/04/20
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param array the result of a query which retreives (all)
- * the tree data from a DB
- * @return array the result
- */
- function setup($res = null)
- {
- if ($res == null) {
- //
- $whereAddOn = '';
- if ($this->options['whereAddOn']) {
- $whereAddOn = 'WHERE '.$this->getOption('whereAddOn');
- }
-
- //
- $orderBy = 'left';
- if ($order = $this->getOption('order')) {
- $orderBy = $order;
- }
-
- // build the query this way, that the root, which has no parent
- // (parentId=0) is first
- $query = sprintf('SELECT * FROM %s %s ORDER BY %s',
- $this->table,
- $whereAddOn,
- // sort by the left-column, so we have the data
- //sorted as it is supposed to be :-)
- $this->_getColName($orderBy)
- );
- if (MDB2::isError($res = $this->dbh->queryAll($query))) {
- return Tree::raiseError('TREE_ERROR_DB_ERROR', $res->getMessage());
- }
- }
-
- return $this->_prepareResults($res);
- }
-
-}
\ No newline at end of file
Index: Tree/Memory/DBnested.php
===================================================================
--- Tree/Memory/DBnested.php (.../branches/Tree_0_3_0) (revision 321102)
+++ Tree/Memory/DBnested.php (.../trunk) (revision 321102)
@@ -1,76 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4: */
-// +----------------------------------------------------------------------+
-// | PHP Version 4 |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2003 The PHP Group |
-// +----------------------------------------------------------------------+
-// | This source file is subject to version 2.02 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: |
-// +----------------------------------------------------------------------+
-//
-// $Id$
-
-require_once 'Tree/Dynamic/DBnested.php';
-
-/**
- *
- *
- * @access public
- * @author
- * @package Tree
- */
-class Tree_Memory_DBnested extends Tree_Dynamic_DBnested
-{
-
- /**
- * retreive all the data from the db and prepare the data so the structure
- * can be built in the parent class
- *
- * @version 2002/04/20
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param array the result of a query which retreives (all)
- * the tree data from a DB
- * @return array the result
- */
- function setup($res = null)
- {
- if ($res == null) {
- //
- $whereAddOn = '';
- if ($this->options['whereAddOn']) {
- $whereAddOn = 'WHERE '.$this->getOption('whereAddOn');
- }
-
- //
- $orderBy = 'left';
- if ($order = $this->getOption('order')) {
- $orderBy = $order;
- }
-
- // build the query this way, that the root, which has no parent
- // (parentId=0) is first
- $query = sprintf('SELECT * FROM %s %s ORDER BY %s',
- $this->table,
- $whereAddOn,
- // sort by the left-column, so we have the data
- //sorted as it is supposed to be :-)
- $this->_getColName($orderBy)
- );
- if (DB::isError($res = $this->dbh->getAll($query))) {
- return $this->_throwError($res->getMessage(),__LINE__);
- }
- }
-
- return $this->_prepareResults( $res );
- }
-
-}
\ No newline at end of file
Index: Tree/Memory/SQLsimple.php
===================================================================
--- Tree/Memory/SQLsimple.php (.../branches/Tree_0_3_0) (revision 0)
+++ Tree/Memory/SQLsimple.php (.../trunk) (revision 321102)
@@ -0,0 +1,264 @@
+<?php
+
+// +----------------------------------------------------------------------+
+// | PHP Version 4 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1997-2005 The PHP Group |
+// +----------------------------------------------------------------------+
+// | This source file is subject to version 2.02 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: Wolfram Kriesing <wolfram@kriesing.de> |
+// | Lorenzo Alberton <l.alberton@quipo.it> |
+// | Helgi Þormar Þorbjörnsson <dufuz@php.net> |
+// +----------------------------------------------------------------------+
+
+// $Id$
+
+require_once 'Tree/Memory.php';
+
+/**
+* the SQL interface to the tree class
+*
+* @access public
+* @author Wolfram Kriesing <wolfram@kriesing.de>
+* @author Helgi Þormar Þorbjörnsson <dufuz@php.net>
+* @author Lorenzo Alberton <l.alberton@quipo.it>
+* @package Tree
+*/
+class Tree_Memory_SQLsimple extends Tree_Memory
+{
+ // {{{ Tree_Memory_MDBsimple()
+
+ /**
+ * set up this object
+ *
+ * @access public
+ * @param string $dsn this is a DSN of the for that PEAR::DB uses it
+ * only that additionally you can add parameters like ...?table=test_table
+ * to define the table it shall work on
+ * @param array $options additional options you can set
+ */
+ function Tree_Memory_SQLsimple($config)
+ {
+ $this->_construct($config);
+ }
+
+ function __construct($config)
+ {
+ $this->conf = Tree::arrayMergeClobber($this->conf, $config['options']);
+ $this->init($config);
+ }
+
+ // }}}
+ // {{{ setup()
+
+ /**
+ * retrieve all the navigation data from the db and call build to build the
+ * tree in the array data and structure
+ *
+ * @access public
+ * @return boolean true on success
+ */
+ function setup()
+ {
+ // TODO sort by prevId (parent_id, prevId $addQuery) too if it exists in the table,
+ // or the root might be wrong, since the prevId of the root should be 0
+
+ $where = $this->conf['whereAddOn']
+ ? 'WHERE ' . $this->conf['whereAddOn'] : '';
+
+ $order = $this->conf['order'] ? ',' . $this->conf['order'] : '';
+
+ $order = $this->conf['fields']['parent_id']['name'] . $order;
+
+ // build the query this way, that the root, which has no parent (parent_id=0)
+ // and no previous (prevId=0) is in first place (in case prevId is given)
+ $query = sprintf("SELECT * FROM %s %s ORDER BY %s",
+ $this->conf['table'],
+ $where,
+ $order); //,prevId !!!!
+ $res = $this->_storage->queryAll($query, array(), false, false);
+ if (PEAR::isError($res)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $res->getMessage());
+ }
+ // if the db-column names need to be mapped to different names
+ // FIXXME somehow we should be able to do this in the query, but I dont know
+ // how to select only those columns, use "as" on them and select the rest,
+ //without getting those columns again :-(
+ $res = $this->_prepareResults($res);
+
+ return $res;
+ }
+
+ // }}}
+ // {{{ add()
+
+ /**
+ * adds _one_ new element in the tree under the given parent
+ * the values' keys given have to match the db-columns, because the
+ * value gets inserted in the db directly
+ * to add an entire node containing children and so on see 'addNode()'
+ *
+ * to be compatible with the MDBnested, u can also give the parent and previd
+ * as the second and third parameter
+ *
+ * @see addNode
+ * @access public
+ * @param array $newValues this array contains the values that shall be inserted in the db-table
+ * the key for each element is the name of the column
+ * @return mixed either boolean false on failure or the id of the inserted row
+ */
+ function add($data, $parent_id = 0)
+ {
+ // FIXXME use $this->dbc->tableInfo to check which columns exist
+ // so only data for which a column exist is inserted
+ if ($parent_id) {
+ $data['parent_id'] = $parent_id;
+ }
+
+ $newData = array();
+ foreach ($data as $key => $value) {
+ // quote the values, as needed for the insert
+ $type = $this->conf['fields'][$key]['type'];
+ $name = $this->_getColName($key);
+ $newData[$name] = $this->_storage->quote($value, $type);
+ }
+
+ // use sequences to create a new id in the db-table
+ $id = $this->_storage->nextId($this->conf['table']);
+ if (PEAR::isError($id)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $id->getMessage() . '-' . $id->getUserInfo());
+ }
+
+ $query = sprintf("INSERT INTO %s (%s, %s) VALUES (%s, %s)",
+ $this->conf['table'] ,
+ $this->_getColName('id'),
+ implode(', ', array_keys($newData)) ,
+ $id,
+ implode(', ', $newData));
+ $result = $this->_storage->query($query);
+ if (PEAR::isError($result)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $result->getMessage() . '-' . $result->getUserInfo());
+ }
+
+ return $id;
+ }
+
+ // }}}
+ // {{{ remove()
+
+ /**
+ * removes the given node
+ *
+ * @access public
+ * @param mixed $id the id of the node to be removed, or an array of id's to be removed
+ * @return boolean true on success
+ */
+ function remove($id)
+ {
+ // if the one to remove has children, get their id's to remove them too
+ if ($this->hasChildren($id)) {
+ $id = $this->walk(array('_remove', $this), $id, 'array');
+ } else {
+ $id = array($id);
+ }
+
+ $where = "
+ WHERE {$this->conf['fields']['id']['name']}
+ IN (" . implode(', ', $id) . ')';
+
+ $query = 'DELETE FROM ' . $this->conf['table'] . $where;
+ $result = $this->_storage->query($query);
+ if (PEAR::isError($result)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $result->getMessage() . '-' . $result->getUserInfo());
+ }
+
+ // TODO if remove succeeded set prevId of the following element properly
+ return true;
+ }
+
+ // }}}
+ // {{{ move()
+
+ /**
+ * move an entry under a given parent or behind a given entry
+ *
+ * @version 2001/10/10
+ * @access public
+ * @author Wolfram Kriesing <wolfram@kriesing.de>
+ * @param integer $idToMove the id of the element that shall be moved
+ * @param integer $newparent_id the id of the element which will be the new parent
+ * @param integer $newPrevId if prevId is given the element with the id idToMove
+ * shall be moved _behind_ the element with id=prevId
+ * if it is 0 it will be put at the beginning
+ * if no prevId is in the DB it can be 0 too and won't bother
+ * since it is not written in the DB anyway
+ * @return boolean true for success
+ */
+ function move($idToMove, $newParent, $newPrevId = 0)
+ {
+ $idName = $this->conf['fields']['id']['name'];
+ $parentName = $this->conf['fields']['parent_id']['name'];
+
+ // FIXXME todo: previous stuff
+ // set the parent in the DB
+ $query = "
+ UPDATE {$this->conf['table']} SET
+ $parentName = $newParent
+ WHERE $idName = $idToMove";
+ $result = $this->_storage->query($query);
+ if (PEAR::isError($result)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $result->getMessage() . '-' . $result->getUserInfo());
+ }
+ // FIXXME update the prevId's of the elements where the element was moved away from and moved in
+ return true;
+ }
+
+ // }}}
+ // {{{ update()
+
+ /**
+ * update an element in the DB
+ *
+ * @version 2002/01/17
+ * @access public
+ * @author Wolfram Kriesing <wolfram@kriesing.de>
+ * @param array $newData all the new data, the key 'id' is used to
+ build the 'WHERE id=' clause and all the other
+ * elements are the data to fill in the DB
+ * @return boolean true for success
+ */
+ function update($id, $data)
+ {
+ // FIXXME check $this->dbc->tableInfo to see if all the columns that shall be updated
+ // really exist, this will also extract nextId etc. if given before writing it in the DB
+ // in case they dont exist in the DB
+ $setData = array();
+ foreach ($data as $key => $value) { // quote the values, as needed for the insert
+ $type = $this->conf['fields'][$key]['type'];
+ $setData[] = $this->_getColName($key) . ' = ' . $this->_storage->quote($value, $type);
+ }
+
+ $query = sprintf('UPDATE %s SET %s WHERE %s = %s',
+ $this->conf['table'],
+ implode(',', $setData),
+ $this->_getColName('id'),
+ $id
+ );
+ $result = $this->_storage->query($query);
+ if (PEAR::isError($result)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $result->getMessage() . '-' . $result->getUserInfo());
+ }
+
+ return true;
+ }
+
+ // }}}
+}
+?>
\ No newline at end of file
Property changes on: Tree/Memory/SQLsimple.php
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
Added: svn:keywords
## -0,0 +1 ##
+Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.1
Index: Tree/Memory/Simple.php
===================================================================
--- Tree/Memory/Simple.php (.../branches/Tree_0_3_0) (revision 0)
+++ Tree/Memory/Simple.php (.../trunk) (revision 321102)
@@ -0,0 +1,62 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+// +----------------------------------------------------------------------+
+// | PHP Version 4 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1997-2005 The PHP Group |
+// +----------------------------------------------------------------------+
+// | This source file is subject to version 3.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/3_0.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: |
+// +----------------------------------------------------------------------+
+//
+// $Id$
+
+require_once 'Tree/Memory.php';
+
+class Tree_Memory_Simple extends Tree_Memory {
+
+ function setup()
+ {
+ $this->_storage->select();
+ }
+
+ function add($data, $parentId = 0)
+ {
+ $this->_storage->insert();
+ }
+
+ function remove($id)
+ {
+ // if the one to remove has children, get their id's to remove them too
+ if ($this->hasChildren($id)) {
+ $id = $this->walk(array('_remove', $this), $id, 'array');
+ } else {
+ $id = array($id);
+ }
+
+ $result = $this->_storage->remove();
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+
+ return true;
+ }
+
+ function update($id, $data)
+ {
+ $this->_storage->update();
+ }
+
+ function move($idToMove, $newParent, $newPrevId = 0)
+ {
+ $this->_storage->update();
+ }
+}
+?>
\ No newline at end of file
Property changes on: Tree/Memory/Simple.php
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
Added: svn:keywords
## -0,0 +1 ##
+Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.1
Index: Tree/Memory/Array.php
===================================================================
--- Tree/Memory/Array.php (.../branches/Tree_0_3_0) (revision 321102)
+++ Tree/Memory/Array.php (.../trunk) (revision 321102)
@@ -3,12 +3,12 @@
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2003 The PHP Group |
+// | Copyright (c) 1997-2005 The PHP Group |
// +----------------------------------------------------------------------+
-// | This source file is subject to version 2.02 of the PHP license, |
+// | This source file is subject to version 3.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. |
+// | http://www.php.net/license/3_0.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. |
@@ -18,8 +18,6 @@
//
// $Id$
-require_once 'Tree/Error.php';
-
/**
* EXPERIMENTAL
*
@@ -86,7 +84,7 @@
* so methods like 'add' etc can find the elements they are searching for,
* if you dont like your data to be modified dont pass them as reference!
*/
- function _setup(&$array, $parentId = 0)
+ function _setup(&$array, $parent_id = 0)
{
foreach ($array as $nodeKey => $aNode) {
$newData = $aNode;
@@ -103,7 +101,7 @@
}
}
// set the parent-id, since we only have a 'children' array
- $newData['parentId'] = $parentId;
+ $newData['parent_id'] = $parent_id;
$children = null;
// remove the 'children' array, since this is only info for
// this class
@@ -138,59 +136,16 @@
foreach ($data as $aNode) {
foreach ($aNode as $key => $val) {
- if (is_array($val) || in_array($key,$unsetKeys)) {
+ if (is_array($val) || in_array($key, $unsetKeys)) {
unset($aNode[$key]);
}
}
- $this->add($aNode,$aNode['parentId']);
+ $this->add($aNode,$aNode['parent_id']);
}
$this->_array = $this->_array['children'][0];
}
// }}}
- // {{{ _prepareResults()
-
- /**
- * prepare multiple results
- *
- * @see _prepareResult()
- * @access private
- * @version 2002/03/03
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- */
- function _prepareResults($results)
- {
- $newResults = array();
- foreach($results as $aResult) {
- $newResults[] = $this->_prepareResult($aResult);
- }
- return $newResults;
- }
-
- // }}}
- // {{{ _prepareResult()
-
- /**
- * map back the index names to get what is expected
- *
- * @access private
- * @version 2002/03/03
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- */
- function _prepareResult($result)
- {
- $map = $this->getOption('columnNameMaps');
-
- if ($map) {
- foreach($map as $key => $columnName) {
- $result[$key] = $result[$columnName];
- unset($result[$columnName]);
- }
- }
- return $result;
- }
-
- // }}}
// {{{ add()
/**
@@ -201,7 +156,7 @@
* @param int the ID of the parent node
* @param int the ID of the previous node
*/
- function add($data, $parentId, $previousId = null)
+ function add($data, $parent_id, $previousId = null)
{
if (!isset($data['id'])) {
$data['id'] = ++$this->_id;
@@ -210,17 +165,17 @@
// the $this->_id if the data['id'] has a higher number.
$this->_id = (int)$data['id'];
}
- $data['parentId'] = $parentId;
+ $data['parent_id'] = $parent_id;
$this->data[$data['id']] = $data;
// there might not be a root element yet
if (!isset($this->_array['children'])) {
- $data['parentId'] = 0;
+ $data['parent_id'] = 0;
$this->_array['children'][] = $data;
} else {
array_walk($this->_array['children'],
- array(&$this,'_add'),
- array($data,$parentId,$previousId)
+ array(&$this, '_add'),
+ array($data, $parent_id, $previousId)
);
}
return $data['id'];
@@ -244,7 +199,7 @@
*/
function _add(&$val, $key, $data)
{
- // is the id of the current elment ($val) == to the parentId ($data[1])
+ // is the id of the current elment ($val) == to the parent_id ($data[1])
if ($val['id'] == $data[1]) {
if (isset($data[2]) && $data[2] === 0) {
// if the previousId is 0 means, add it as the first member
@@ -254,7 +209,7 @@
}
} else { // if we havent found the new element go on searching
if (isset($val['children'])) {
- array_walk($val['children'],array(&$this,'_add'),$data);
+ array_walk($val['children'],array(&$this, '_add'), $data);
}
}
}
@@ -270,16 +225,16 @@
* @param array the data, [key]=>[value]
* @return void
*/
- function update($id,$data)
+ function update($id, $data)
{
- if ($this->_array['id']==$id) {
- foreach ($data as $key=>$newVal) {
+ if ($this->_array['id'] == $id) {
+ foreach ($data as $key => $newVal) {
$this->_array[$key] = $newVal;
}
} else {
array_walk($this->_array['children'],
- array(&$this,'_update'),
- array($id,$data)
+ array(&$this, '_update'),
+ array($id, $data)
);
}
}
@@ -300,7 +255,7 @@
*/
function _update(&$val, $key, $data)
{
- // is the id of the current elment ($val) == to the parentId ($data[1])
+ // is the id of the current elment ($val) == to the parent_id ($data[1])
if ($val['id'] == $data[0]) {
foreach ($data[1] as $key => $newVal) {
$val[$key] = $newVal;
@@ -309,7 +264,7 @@
// if we havent found the new element go on searching
// in the children
if (isset($val['children'])) {
- array_walk($val['children'],array(&$this,'_update'), $data);
+ array_walk($val['children'],array(&$this, '_update'), $data);
}
}
}
@@ -328,7 +283,7 @@
// we only need to search for element that do exist :-)
// otherwise we save some processing time
if ($this->data[$id]) {
- $this->_remove($this->_array,$id);
+ $this->_remove($this->_array, $id);
}
}
@@ -350,17 +305,18 @@
if (isset($val['children'])) {
foreach ($val['children'] as $key => $aVal) {
if ($aVal['id'] == $id) {
- if (sizeof($val['children']) < 2) {
+ if (count($val['children']) < 2) {
unset($val['children']);
} else {
unset($val['children'][$key]);
}
} else {
- $this->_remove($val['children'][$key],$id);
+ $this->_remove($val['children'][$key], $id);
}
}
}
}
// }}}
-}
\ No newline at end of file
+}
+?>
\ No newline at end of file
Property changes on: Tree/Memory/Array.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.14.2.2
+1.15
Index: Tree/Memory/XML.php
===================================================================
--- Tree/Memory/XML.php (.../branches/Tree_0_3_0) (revision 321102)
+++ Tree/Memory/XML.php (.../trunk) (revision 321102)
@@ -3,12 +3,12 @@
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2003 The PHP Group |
+// | Copyright (c) 1997-2005 The PHP Group |
// +----------------------------------------------------------------------+
-// | This source file is subject to version 2.02 of the PHP license, |
+// | This source file is subject to version 3.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. |
+// | http://www.php.net/license/3_0.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. |
@@ -30,7 +30,6 @@
*/
class Tree_Memory_XML extends XML_Parser
{
-
/**
* @var array the first element has to be empty, so we can use
* the parentId=0 as "no parent"
@@ -72,9 +71,9 @@
* @author Wolfram Kriesing <wolfram@kriesing.de>
* @return boolean true on success
*/
- function Tree_Memory_XML($dsn, $options)
+ function Tree_Memory_XML($config)
{
- $handle = $dsn;
+ $handle = $config['storage']['dsn'];
$this->XML_Parser();
@@ -100,12 +99,12 @@
*/
function startHandler($parser, $element, $attribs)
{
- $elementBeforeId = sizeof($this->data) - 1;
- $curId = sizeof($this->data);
+ $elementBeforeId = count($this->data) - 1;
+ $curId = count($this->data);
$this->data[$curId]['id'] = $curId;
- $this->data[$curId]['name'] = $this->_toLower?
- strtolower($element):$element;
+ $this->data[$curId]['name'] = $this->_toLower ?
+ strtolower($element) : $element;
$this->data[$curId]['level'] = $this->level;
$this->data[$curId]['attributes'] = $attribs;
if ($this->_toLower) {
@@ -168,11 +167,11 @@
# ANSWER: if you call xml_parse($parser, "foo ", false) and then
# xml_parse($parser, "bar", true), callbacks are done once
# for each xml_parse() call.
- if (!isset($this->data[ sizeof($this->data)-1 ]['cdata'])) {
- $this->data[ sizeof($this->data)-1 ]['cdata'] = '';
+ if (!isset($this->data[count($this->data) - 1]['cdata'])) {
+ $this->data[count($this->data) - 1]['cdata'] = '';
}
#print "cdata = '$cdata'\r\n";
- $this->data[ sizeof($this->data)-1 ]['cdata'].= $cdata;
+ $this->data[count($this->data) - 1]['cdata'].= $cdata;
}
// }}}
@@ -188,7 +187,7 @@
*/
function defaultHandler($parser, $cdata)
{
- // $this->data[ sizeof($this->data)-1 ]['cdata'] = $cdata;
+ // $this->data[ count($this->data)-1 ]['cdata'] = $cdata;
// not in use yet :-( is that ok??
}
@@ -252,7 +251,7 @@
/* function add($newValues)
{
// add the data in the internal structure $this->data
- $this->data[sizeof($this->data)] = $newValues;
+ $this->data[count($this->data)] = $newValues;
# i am thinking if it might be a good solution to walk the data-array
# and write each line singlely until the one to add comes, write it and
@@ -312,4 +311,5 @@
}
*/
-}
\ No newline at end of file
+}
+?>
Property changes on: Tree/Memory/XML.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.11.2.1
+1.12
Index: Tree/Memory/SQLnested.php
===================================================================
--- Tree/Memory/SQLnested.php (.../branches/Tree_0_3_0) (revision 0)
+++ Tree/Memory/SQLnested.php (.../trunk) (revision 321102)
@@ -0,0 +1,78 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+// +----------------------------------------------------------------------+
+// | PHP Version 4 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1997-2003 The PHP Group |
+// +----------------------------------------------------------------------+
+// | This source file is subject to version 2.02 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: |
+// +----------------------------------------------------------------------+
+//
+// $Id$
+
+require_once 'Tree/Dynamic/SQLnested.php';
+
+/**
+ *
+ *
+ * @access public
+ * @author
+ * @package Tree
+ */
+class Tree_Memory_SQLnested extends Tree_Dynamic_SQLnested
+{
+ /**
+ * retreive all the data from the db and prepare the data so the structure
+ * can be built in the parent class
+ *
+ * @version 2002/04/20
+ * @access public
+ * @author Wolfram Kriesing <wolfram@kriesing.de>
+ * @param array the result of a query which retreives (all)
+ * the tree data from a DB
+ * @return array the result
+ */
+ function setup($res = null)
+ {
+ if ($res == null) {
+ //
+ $whereAddOn = '';
+ if ($this->conf['whereAddOn']) {
+ $whereAddOn = 'WHERE '.$this->conf['whereAddOn'];
+ }
+
+ //
+ $orderBy = 'left';
+ if ($order = $this->conf['order']) {
+ $orderBy = $order;
+ }
+
+ // build the query this way, that the root, which has no parent
+ // (parent_id=0) is first
+ $query = sprintf('SELECT * FROM %s %s ORDER BY %s',
+ $this->conf['table'],
+ $whereAddOn,
+ // sort by the left-column, so we have the data
+ //sorted as it is supposed to be :-)
+ $this->_getColName($orderBy)
+ );
+ $res = $this->_storage->queryAll($query, array(), false, false);
+ if (PEAR::isError($res)) {
+ return Tree::raiseError(TREE_ERROR_DB_ERROR, null, null, $res->getMessage());
+ }
+ }
+
+ return $this->_prepareResults($res);
+ }
+
+}
+
+?>
\ No newline at end of file
Property changes on: Tree/Memory/SQLnested.php
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
Added: svn:keywords
## -0,0 +1 ##
+Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.1
Index: Tree/Memory/Filesystem.php
===================================================================
--- Tree/Memory/Filesystem.php (.../branches/Tree_0_3_0) (revision 321102)
+++ Tree/Memory/Filesystem.php (.../trunk) (revision 321102)
@@ -3,7 +3,7 @@
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2003 The PHP Group |
+// | Copyright (c) 1997-2005 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
@@ -18,8 +18,6 @@
//
// $Id$
-require_once 'Tree/Error.php';
-
/**
* the Filesystem interface to the tree class
* this is a bit different, as id we use the entire path, since we know
@@ -35,6 +33,9 @@
* I also thought about hashing the path name but then the add method is
* not that easy to implement ... may be one day :-)
*
+ * Use the System class
+ * http://cvs.php.net/pear-core/System.php
+ *
* @access public
* @author Wolfram Kriesing <wolfram@kriesing.de>
* @version 2001/06/27
@@ -47,9 +48,9 @@
* @access public
* @var array saves the options passed to the constructor
*/
- var $options = array(
+ var $conf = array(
'order' => '',
- 'columnNameMaps' => array(),
+ 'fields' => array(),
);
// {{{ Tree_Memory_Filesystem()
@@ -63,7 +64,7 @@
* @param string $dsn the path on the filesystem
* @param array $options additional options you can set
*/
- function Tree_Memory_Filesystem ($path, $options = array())
+ function Tree_Memory_Filesystem($path, $options = array())
{
$this->_path = $path;
// not in use currently
@@ -135,8 +136,7 @@
# FIXXME do the mapping
if (!@mkdir("$parent/{$newValues['name']}", 0700)) {
return $this->_raiseError(TREE_ERROR_CANNOT_CREATE_FOLDER,
- $newValues['name'].' under '.$parent,
- __LINE__
+ $newValues['name'].' under '.$parent
);
}
return "$parent/{$newValues['name']}";
@@ -206,7 +206,7 @@
*/
function _prepareResult($result)
{
- $map = $this->getOption('columnNameMaps');
+ $map = $this->getOption('fields');
if ($map) {
foreach ($map as $key => $columnName) {
$result[$key] = $result[$columnName];
@@ -217,4 +217,5 @@
}
// }}}
-}
\ No newline at end of file
+}
+?>
\ No newline at end of file
Property changes on: Tree/Memory/Filesystem.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.9.2.2
+1.10
Index: Tree/Storage.php
===================================================================
--- Tree/Storage.php (.../branches/Tree_0_3_0) (revision 0)
+++ Tree/Storage.php (.../trunk) (revision 321102)
@@ -0,0 +1,102 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * A framework for authentication and authorization in PHP applications
+ *
+ * LiveUser_Admin is meant to be used with the LiveUser package.
+ * It is composed of all the classes necessary to administrate
+ * data used by LiveUser.
+ *
+ * You'll be able to add/edit/delete/get things like:
+ * * Rights
+ * * Users
+ * * Groups
+ * * Areas
+ * * Applications
+ * * Subgroups
+ * * ImpliedRights
+ *
+ * And all other entities within LiveUser.
+ *
+ * At the moment we support the following storage containers:
+ * * DB
+ * * MDB
+ * * MDB2
+ *
+ * But it takes no time to write up your own storage container,
+ * so if you like to use native mysql functions straight, then it's possible
+ * to do so in under a hour!
+ *
+ * PHP version 4 and 5
+ *
+ * LICENSE: This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ *
+ * @category authentication
+ * @package LiveUser_Admin
+ * @author Markus Wolff <wolff@21st.de>
+ * @author Helgi Þormar Þorbjörnsson <dufuz@php.net>
+ * @author Lukas Smith <smith@backendmedia.com>
+ * @author Arnaud Limbourg <arnaud@php.net>
+ * @author Christian Dickmann <dickmann@php.net>
+ * @author Matt Scifo <mscifo@php.net>
+ * @author Bjoern Kraus <krausbn@php.net>
+ * @copyright 2002-2005 Markus Wolff
+ * @license http://www.gnu.org/licenses/lgpl.txt
+ * @version CVS: $Id$
+ * @link http://pear.php.net/LiveUser_Admin
+ */
+
+/**
+ * This is a PEAR::MDB2 backend driver for the LiveUser class.
+ * A PEAR::MDB2 connection object can be passed to the constructor to reuse an
+ * existing connection. Alternatively, a DSN can be passed to open a new one.
+ *
+ * Requirements:
+ * - File "Liveuser.php" (contains the parent class "LiveUser")
+ * - Array of connection options or a PEAR::MDB2 connection object must be
+ * passed to the constructor.
+ * Example: array('dsn' => 'mysql://user:pass@host/db_name')
+ * OR
+ * &$conn (PEAR::MDB2 connection object)
+ *
+ * @category authentication
+ * @package LiveUser_Admin
+ * @author Lukas Smith <smith@backendmedia.com>
+ * @author Bjoern Kraus <krausbn@php.net>
+ * @copyright 2002-2005 Markus Wolff
+ * @license http://www.gnu.org/licenses/lgpl.txt
+ * @version Release: @package_version@
+ * @link http://pear.php.net/LiveUser_Admin
+ */
+class Tree_Storage
+{
+ function init(&$storageConf)
+ {
+ return true;
+ }
+
+ /**
+ * properly disconnect from resources
+ *
+ * @access public
+ */
+ function disconnect()
+ {
+ }
+}
+?>
Property changes on: Tree/Storage.php
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
Added: svn:keywords
## -0,0 +1 ##
+Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.1
Index: Tree/Memory.php
===================================================================
--- Tree/Memory.php (.../branches/Tree_0_3_0) (revision 321102)
+++ Tree/Memory.php (.../trunk) (revision 321102)
@@ -3,7 +3,7 @@
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2003 The PHP Group |
+// | Copyright (c) 1997-2005 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
@@ -18,7 +18,7 @@
//
// $Id$
-require_once 'Tree/Common.php';
+require_once 'Tree/Tree.php';
/**
* this class can be used to step through a tree using ['parent'],['child']
@@ -42,7 +42,7 @@
* +---level 1_2 (5)
*
* the database table to this structure (without defined order)
- * id parentId name
+ * id parent_id name
* 1 0 level 1_1
* 2 1 level 2_1
* 3 1 level 2_1
@@ -87,7 +87,7 @@
* @version 2001/06/27
* @package Tree
*/
-class Tree_Memory extends Tree_Common
+class Tree_Memory extends Tree
{
/**
* this array contains the pure data from the DB
@@ -112,7 +112,7 @@
var $structure = array();
/**
- * it contains all the parents and their children, where the parentId is the
+ * it contains all the parents and their children, where the parent_id is the
* key and all the children are the values, this is for speeding up
* the tree-building process
*
@@ -121,22 +121,6 @@
var $children = array();
/**
- * @access private
- * @var boolean saves if tree nodes shall be removed recursively
- * @see setRemoveRecursively()
- */
- var $removeRecursively = false;
-
-
- /**
- * @access public
- * @var integer the debug mode, if > 0 then debug info are shown,
- * actually those messages only show performance
- * times
- */
- var $debug = 0;
-
- /**
* @see &getNode()
* @see &_getNode()
* @access private
@@ -160,6 +144,8 @@
*/
var $_treeDepth = 0;
+ var $walkReturn = array();
+
// {{{ Tree_Memory()
/**
@@ -172,24 +158,33 @@
* either an object/string
* @param array additional options you can set
*/
- function Tree_Memory($type, $dsn = '', $options = array())
+ function Tree_Memory($config)
{
- // set the options for $this
- $this->Tree_Options($options);
- include_once "Tree/Memory/$type.php";
- $className = 'Tree_Memory_'.$type;
- $this->dataSourceClass =& new $className($dsn, $options);
+ $this->__construct($config);
+ }
- // copy the options to be able to get them via getOption(s)
- // FIXXME this is not really cool, maybe overwrite
- // the *Option* methods!!!
- if (isset($this->dataSourceClass->options)) {
- $this->options = $this->dataSourceClass->options;
+ function __construct($config)
+ {
+ $type = strtolower($config['type']);
+ $this->conf = Tree::arrayMergeClobber($this->conf, $config['options']);
+ if (
+ ($type == 'simple' || $type == 'nested')
+ && in_array(strtoupper($config['storage']['name']), array('DB', 'MDB', 'MDB2'))
+ ) {
+ $name = 'SQL';
+ } else {
+ $name = strtoupper($config['storage']['name']);
}
+ include_once 'Tree/Memory/' . $name . $type . '.php';
+ $className = 'Tree_Memory_' . $name . $type;
+
+ $this->dataClass = new $className($config);
}
// }}}
+
+
// {{{ switchDataSource()
/**
@@ -208,15 +203,15 @@
* @param array additional options you can set
* @return boolean true on success
*/
- function switchDataSource($type, $dsn = '', $options = array())
+ function switchDataSource($config)
{
$data = $this->getNode();
//$this->Tree($dsn, $options);
- $this->Tree_Memory($type, $GLOBALS['dummy'], $options);
+ $this->Tree_Memory($config);
// this method prepares data retreived using getNode to be used
// in this type of tree
- $this->dataSourceClass->setData($data);
+ $this->dataClass->setData($data);
$this->setup();
}
@@ -238,7 +233,7 @@
// for XML an XML-String,
// for DB-a result set, may be or an array, dont know here
// not implemented yet
- $res = $this->dataSourceClass->setupByRawData($string);
+ $res = $this->dataClass->setupByRawData($string);
return $this->_setup($res);
}
@@ -255,22 +250,11 @@
*/
function setup($data = null)
{
- if ($this->debug) {
- $startTime = split(' ',microtime());
- $startTime = $startTime[1]+$startTime[0];
- }
-
- if (PEAR::isError($res = $this->dataSourceClass->setup($data))) {
+ $res = $this->dataClass->setup($data);
+ if (PEAR::isError($res)) {
return $res;
}
- if ($this->debug) {
- $endTime = split(' ',microtime());
- $endTime = $endTime[1]+$endTime[0];
- echo ' reading and preparing tree data took: '.
- ($endTime - $startTime) . '<br>';
- }
-
return $this->_setup($res);
}
@@ -288,7 +272,7 @@
*/
function _setup($setupData)
{
- // TODO sort by prevId (parentId,prevId $addQuery) too if it exists
+ // TODO sort by prevId (parent_id,prevId $addQuery) too if it exists
// in the table, or the root might be wrong TODO since the prevId
// of the root should be 0
if (!$setupData) {
@@ -296,23 +280,52 @@
}
//FIXXXXXME validate the structure.
- // i.e. a problem occurs, if you give one node, which has a parentId=1,
+ // i.e. a problem occurs, if you give one node, which has a parent_id=1,
// it screws up everything!!!
//empty the data structures, since we are reading the data
// from the db (again)
- $this->structure = array();
- $this->data = array();
- $this->children = array();
+ $this->structure = $this->data = $this->children = array();
+
// build an array where all the parents have their children as a member
// this i do to speed up the buildStructure
- $columnNameMappings = $this->getOption('columnNameMaps');
- foreach ($setupData as $values) {
+ $copy = $setupData;
+ foreach ($setupData as $key => $values) {
if (is_array($values)) {
$this->data[$values['id']] = $values;
- $this->children[$values['parentId']][] = $values['id'];
+ $this->children[$values['parent_id']][] = $values['id'];
+ $this->structure[$values['id']] = $values['parent_id'];
+
+ if ($values['parent_id'] == '0') {
+ $this->data[$values['id']]['level'] = 0;
+ unset($copy[$key]);
+ }
+ } else {
+ unset($copy[$key]);
}
}
+ unset($setupData);
+ // Get the levels for each item.
+ do {
+ foreach ($copy as $key => $node) {
+ if (!array_key_exists('parent_id', $node)) {
+ unset($copy[$key]);
+ continue;
+ }
+
+ if (isset($this->data[$node['parent_id']]['level'])) {
+ $level = $this->data[$node['parent_id']]['level'] + 1;
+ $this->data[$node['id']]['level'] = $level;
+
+ if ($level > $this->_treeDepth) {
+ $this->_treeDepth = $level;
+ }
+ unset($copy[$key]);
+ }
+ }
+ } while (count($copy));
+ unset($copy);
+
// walk through all the children on each level and set the
// next/previous relations of those children, since all children
// for "children[$id]" are on the same level we can do
@@ -325,93 +338,14 @@
// remember the nextId too, so the build process can
// be speed up
$this->data[$lastPrevId]['nextId'] = $key;
- $this->data[$lastPrevId]['next'] = &$this->data[$key];
$this->data[$key]['prevId'] = $lastPrevId;
- $this->data[$key]['previous'] = &$this->data[ $lastPrevId ];
}
$lastPrevId = $key;
}
}
}
- if ($this->debug) {
- $startTime = split(' ',microtime());
- $startTime = $startTime[1] + $startTime[0];
- }
-
- // when NO prevId is given, sort the entries in each level by the given
- // sort order (to be defined) and set the prevId so the build can work
- // properly does a prevId exist?
- if (!isset($setupData[0]['prevId'])) {
- $lastPrevId = 0;
- $lastParentId = 0;
- $level = 0;
- // build the entire recursive relations, so you have 'parentId',
- // 'childId', 'nextId', 'prevId' and the references 'child',
- // 'parent', 'next', 'previous' set in the property 'data'
- foreach($this->data as $key => $value) {
- // most if checks in this foreach are for the following reason,
- // if not stated otherwise:
- // dont make an data[''] or data[0] since this was not read
- // from the DB, because id is autoincrement and starts at 1
- // and also in an xml tree there can not be an element </>
- // i hope :-)
- if ($value['parentId']) {
- $this->data[$key]['parent'] = &$this->data[$value['parentId']];
- // the parent has an extra array which contains a reference
- // to all it's children, set it here
- $this->data[ $value['parentId']]['children'][] =
- &$this->data[$key];
- }
-
- // was a child saved (in the above 'if')
- // see comment above
- if (isset($this->children[$key]) &&
- count($this->children[$key])
- ) {
- // refer to the first child in the [child]
- // and [childId] keys
- $this->data[$key]['childId'] = $this->children[$key][0];
- $this->data[$key]['child'] =
- &$this->data[$this->children[$key][0]];
- }
-
- $lastParentId = $value['parentId'];
- }
- }
-
- if ($this->debug) {
- $endTime = split(' ',microtime());
- $endTime = $endTime[1]+$endTime[0];
- echo ' building took: ' . ($endTime - $startTime) . ' <br>';
- }
-
- // build the property 'structure'
- // empty it, just to be sure everything
- //will be set properly
- $this->structure = array();
-
- if ($this->debug) {
- $startTime = split(' ',microtime());
- $startTime = $startTime[1] + $startTime[0];
- }
-
- // build all the children that are on the root level, if we wouldnt
- // do that. We would have to create a root element with an id 0,
- // but since this is not read from the db we dont add another element.
- // The user wants to get what he had saved
- if (isset($this->children[0])) {
- foreach ($this->children[0] as $rootElement) {
- $this->buildStructure($rootElement, $this->structure);
- }
- }
-
- if ($this->debug) {
- $endTime = split(' ',microtime());
- $endTime = $endTime[1] + $endTime[0];
- echo ' buildStructure took: ' . ($endTime - $startTime).' <br>';
- }
return true;
}
@@ -434,16 +368,24 @@
* @return mixed either boolean false on failure or the id
* of the inserted row
*/
- function add($newValues, $parentId = 0, $prevId = 0)
+ function add($data, $parent_id = 0, $prevId = 0)
{
// see comments in 'move' and 'remove'
+ if (method_exists($this->dataClass, 'add')) {
+ $result = $this->dataClass->add($data, $parent_id, $prevId);
+ /*if (!PEAR::isError($result)) {
+ // Setup parent/child relationship
+ $this->children[$parent_id][] = $nextId;
- if (method_exists($this->dataSourceClass, 'add')) {
- return $this->dataSourceClass->add($newValues, $parentId, $prevId);
- } else {
- return $this->_throwError('method not implemented yet.' ,
- __LINE__);
+ // Add to list of nodes
+ $this->structure[$result] = $parent_id;
+
+ // Add data
+ $this->data[$result] = $newValues;
+ }*/
+ return $result;
}
+ return Tree::raiseError('TREE_ERROR_NOT_IMPLEMENTED');
}
// }}}
@@ -460,31 +402,39 @@
*/
function remove($id)
{
- // if removing recursively is not allowed, which means every child
- // should be removed
- // then check if this element has a child and return
- // "sorry baby cant remove :-) "
- if ($this->removeRecursively != true) {
- if (isset($this->data[$id]['child'])) {
- // TODO raise PEAR warning
- return $this->_throwError("Element with id=$id has children ".
- "that cant be removed. Set ".
- "'setRemoveRecursively' to true to ".
- "allow this.",
- __LINE__
- );
- }
- }
-
// see comment in 'move'
// if the prevId is in use we need to update the prevId of the element
// after the one that is removed too, to have the prevId of the one
// that is removed!!!
- if (method_exists($this->dataSourceClass, 'remove')) {
- return $this->dataSourceClass->remove($id);
- } else {
- return $this->_throwError('method not implemented yet.', __LINE__);
+ if (method_exists($this->dataClass, 'remove')) {
+ // Remove child nodes first
+ if (isset($this->children[$id])) {
+ foreach ($this->children[$id] as $child) {
+ $this->remove($child);
+ }
+ }
+
+ $result = $this->dataClass->remove($id);
+ /*if ($result) {
+ // Remove childIDs data
+ if (isset($this->children[$id])) {
+ unset($this->children[$id]);
+ }
+
+ // Remove data
+ if (isset($this->data[$id])) {
+ unset($this->data[$id]);
+ }
+
+ // Remove from structure array
+ if (isset($this->structure[$id])) {
+ unset($this->structure[$id]);
+ }
+ }*/
+ return $result;
}
+
+ return Tree::raiseError('TREE_ERROR_NOT_IMPLEMENTED');
}
// }}}
@@ -505,13 +455,46 @@
}
// }}}
+ // {{{ update()
+
+ /**
+ * update data in a node
+ *
+ * @version 2002/01/29
+ * @access public
+ * @author Wolfram Kriesing <wolfram@kriesing.de>
+ * @param integer the ID of the element that shall be updated
+ * @param array the data to update
+ * @return mixed either boolean or
+ * an error object if the method is not implemented
+ */
+ function update($id, $data)
+ {
+ if (method_exists($this->dataClass, 'update')) {
+ $result = $this->dataClass->update($id, $data);
+ /*if ($result) {
+ // Setup parent/child relationship - Needs to be done a check here to see if it needs unset/add
+ $this->children[$data['parent_id'][] = $id;
+
+ // Add to list of nodes
+ $this->structure[$id] = $data['parent_id'];
+
+ // Update data
+ $this->data[$id] = $data;
+ }*/
+ return $result;
+ }
+ return Tree::raiseError('TREE_ERROR_NOT_IMPLEMENTED');
+ }
+
+ // }}}
// {{{ move()
/**
* move an entry under a given parent or behind a given entry.
* !!! the 'move behind another element' is only implemented for nested
* trees now!!!.
- * If a newPrevId is given the newParentId is dismissed!
+ * If a newPrevId is given the newparent_id is dismissed!
* call it either like this:
* $tree->move(x, y)
* to move the element (or entire tree) with the id x
@@ -542,12 +525,11 @@
* the beginning
* @return boolean true for success
*/
- function move($idsToMove, $newParentId, $newPrevId = 0)
+ function move($idsToMove, $newparent_id, $newPrevId = 0)
{
- settype($idsToMove,'array');
$errors = array();
- foreach ($idsToMove as $idToMove) {
- $ret = $this->_move($idToMove, $newParentId, $newPrevId);
+ foreach ((array)$idsToMove as $idToMove) {
+ $ret = $this->_move($idToMove, $newparent_id, $newPrevId);
if (PEAR::isError($ret)) {
$errors[] = $ret;
}
@@ -577,15 +559,14 @@
* if it is 0 it will be put at the beginning
* @return mixed true for success, Tree_Error on failure
*/
- function _move($idToMove, $newParentId, $prevId = 0)
+ function _move($idToMove, $newparent_id, $prevId = 0)
{
// itself can not be a parent of itself
- if ($idToMove == $newParentId) {
- // TODO PEAR-ize error
- return TREE_ERROR_INVALID_PARENT;
+ if ($idToMove == $newparent_id) {
+ return Tree::raiseError('TREE_ERROR_INVALID_PARENT');
}
- // check if $newParentId is a child (or a child-child ...) of $idToMove
+ // check if $newparent_id is a child (or a child-child ...) of $idToMove
// if so prevent moving, because that is not possible
// does this element have children?
if ($this->hasChildren($idToMove)) {
@@ -595,20 +576,18 @@
// (might, not yet) return a reference use while since foreach
// only works on a copy of the data to loop through, but we are
// changing $allChildren in the loop
- while (list(, $aChild) = each ($allChildren)) {
+ while (list(, $aChild) = each($allChildren)) {
// remove the first element because if array_merge is called
// the array pointer seems to be
array_shift($allChildren);
// set to the beginning and this way the beginning is always
// the current element, simply work off and truncate in front
if (@$aChild['children']) {
- $allChildren = array_merge($allChildren,
- $aChild['children']
- );
+ $allChildren =
+ array_merge($allChildren, $aChild['children']);
}
- if ($newParentId == $aChild['id']) {
- // TODO PEAR-ize error
- return TREE_ERROR_INVALID_PARENT;
+ if ($newparent_id == $aChild['id']) {
+ return Tree::raiseError('TREE_ERROR_INVALID_PARENT');
}
}
}
@@ -617,103 +596,23 @@
// needs to know where the element should be moved to
// and it has to change the prevId of the element that will be after it
// so we may be simply call some method like 'update' too?
- if (method_exists($this->dataSourceClass, 'move')) {
- return $this->dataSourceClass->move($idToMove,
- $newParentId,
+ if (method_exists($this->dataClass, 'move')) {
+ return $this->dataClass->move($idToMove,
+ $newparent_id,
$prevId
);
- } else {
- return $this->_throwError('method not implemented yet.', __LINE__);
}
+ return Tree::raiseError('TREE_ERROR_NOT_IMPLEMENTED');
}
// }}}
- // {{{ update()
- /**
- * update data in a node
- *
- * @version 2002/01/29
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param integer the ID of the element that shall be updated
- * @param array the data to update
- * @return mixed either boolean or
- * an error object if the method is not implemented
- */
- function update($id, $data)
- {
- if (method_exists($this->dataSourceClass, 'update')) {
- return $this->dataSourceClass->update($id,$data);
- } else {
- return $this->_throwError(
- 'method not implemented yet.', __LINE__
- );
- }
- }
-
- // }}}
-
//
//
- // from here all methods are not interacting on the 'dataSourceClass'
+ // from here all methods are not interacting on the 'dataClass'
//
//
- // {{{ buildStructure()
- /**
- * builds the structure in the parameter $insertIn
- * this function works recursively down into depth of the folder structure
- * it builds an array which goes as deep as the structure goes
- *
- * @access public
- * @version 2001/05/02
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param integer the parent for which it's structure shall
- * be built
- * @param integer the array where to build the structure in
- * given as a reference to be sure the substructure is built
- * in the same array as passed to the function
- * @return boolean returns always true
- *
- */
- function buildStructure($parentId, &$insertIn)
- {
- // create the element, so it exists in the property "structure"
- // also if there are no children below
- $insertIn[$parentId] = array();
-
- // set the level, since we are walking through the structure here.
- // Anyway we can do this here, instead of up in the setup method :-)
- // always set the level to one higher than the parent's level, easy ha?
- // this applies only to the root element(s)
- if (isset($this->data[$parentId]['parent']['level'])) {
- $this->data[$parentId]['level'] =
- $this->data[$parentId]['parent']['level']+1;
- if ($this->data[$parentId]['level']>$this->_treeDepth) {
- $this->_treeDepth = $this->data[$parentId]['level'];
- }
- } else {
- // set first level number to 0
- $this->data[$parentId]['level'] = 0;
- }
-
- if (isset($this->children[$parentId])
- && count($this->children[$parentId])) {
- // go thru all the folders
- foreach ($this->children[$parentId] as $child) {
- // build the structure under this folder,
- // use the current folder as the new parent and call
- // build recursively to build all the children by calling build
- // with $insertIn[someindex] the array is filled
- // since the array was empty before
- $this->buildStructure($child, $insertIn[$parentId]);
- }
- }
- return true;
- }
-
- // }}}
// {{{ walk()
/**
@@ -736,15 +635,20 @@
function walk($walkFunction, $id = 0, $returnType = 'string')
{
// by default all of structure is used
- $useNode = $this->structure;
- if ($id == 0) {
+ if ($id === 0) {
+ $useNode = $this->structure;
$keys = array_keys($this->structure);
$id = $keys[0];
} else {
// get the path, to be able to go to the element in this->structure
$path = $this->getPath($id);
+ if (empty($path)) {
+ return array();
+ }
+
// pop off the last element, since it is the one requested
array_pop($path);
+
// start at the root of structure
$curNode = $this->structure;
foreach ($path as $node) {
@@ -787,27 +691,29 @@
*/
function _walk($walkFunction, &$curLevel, $returnType)
{
- if (count($curLevel)) {
+ if (isset($curLevel) && is_array($curLevel)) {
foreach ($curLevel as $key => $value) {
$ret = call_user_func($walkFunction, $this->data[$key]);
+
switch ($returnType) {
- case 'array':
- $this->walkReturn[] = $ret;
- break;
- // this only adds the element if the $ret is an array
- // and contains data
- case 'ifArray':
- if (is_array($ret)) {
+ case 'array':
$this->walkReturn[] = $ret;
- }
- break;
- default:
- $this->walkReturn.= $ret;
- break;
+ break;
+ // this only adds the element if the $ret is an array
+ // and contains data
+ case 'ifArray':
+ if (is_array($ret)) {
+ $this->walkReturn[] = $ret;
+ }
+ break;
+ default:
+ $this->walkReturn .= $ret;
+ break;
}
$this->_walk($walkFunction, $value, $returnType);
}
}
+
return $this->walkReturn;
}
@@ -821,7 +727,7 @@
* one element).
* The following array $x passed as the parameter
* $x[0] = array('name' => 'bla',
- * 'parentId' => '30',
+ * 'parent_id' => '30',
* array('name' => 'bla1',
* 'comment' => 'foo',
* array('name' => 'bla2'),
@@ -830,10 +736,10 @@
* array('name'=>'bla1_1'),
* );
* $x[1] = array('name' => 'fooBla',
- * 'parentId' => '30');
+ * 'parent_id' => '30');
*
* would add the following tree (or subtree/node) under the parent
- * with the id 30 (since 'parentId'=30 in $x[0] and in $x[1]):
+ * with the id 30 (since 'parent_id'=30 in $x[0] and in $x[1]):
* +--bla
* | +--bla1
* | | +--bla2
@@ -867,16 +773,16 @@
}
}
// add the element and get the id, that it got, to have
- // the parentId for the children
+ // the parent_id for the children
$insertedId = $this->add($newEntry);
// if inserting suceeded, we have received the id
// under which we can insert the children
- if ($insertedId!= false) {
- // if there are children, set their parentId.
+ if ($insertedId != false) {
+ // if there are children, set their parent_id.
// So they kknow where they belong in the tree
if (count($newNode)) {
foreach($newNode as $key => $aNewNode) {
- $newNode[$key]['parentId'] = $insertedId;
+ $newNode[$key]['parent_id'] = $insertedId;
}
}
// call yourself recursively to insert the children
@@ -906,17 +812,18 @@
*/
function getPath($id)
{
+ if (!(int)$id) {
+ return array();
+ }
+
// empty the path, to be clean
$path = array();
- // FIXXME may its better to use a for(level) to count down,
- // since a while is always a little risky
- // until there are no more parents
- while (@$this->data[$id]['parent']) {
+ while (@$this->data[$id]['parent_id']) {
// curElement is already a reference, so save it in path
$path[] = &$this->data[$id];
// get the next parent id, for the while to retreive the parent's parent
- $id = $this->data[$id]['parent']['id'];
+ $id = $this->data[$id]['parent_id'];
}
// dont forget the last one
$path[] = &$this->data[$id];
@@ -925,24 +832,6 @@
}
// }}}
- // {{{ setRemoveRecursively()
-
- /**
- * sets the remove-recursively mode, either true or false
- *
- * @version 2001/10/09
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param boolean set to true if removing a tree level
- * shall remove all it's children and theit children
- *
- */
- function setRemoveRecursively($case=true)
- {
- $this->removeRecursively = $case;
- }
-
- // }}}
// {{{ _getElement()
/**
@@ -960,36 +849,15 @@
// element that is requested.
$element = null;
- if ($what == '') {
- $element = $this->data[$id];
+ if ($what == '' && isset($this->data[$id])) {
+ $element = &$this->_prepareResult($this->data[$id]);
}
- $elementId = $this->_getElementId($id, $what);
- if ($elementId !== null) {
- $element = $this->data[$elementId];
+
+ if (isset($this->data[$id][$what])) {
+ $element = &$this->_prepareResult($this->data[$this->data[$id][$what]]);
}
- // we should not return false, since that might be a value
- // of the element that is requested
- return $element;
- }
- // }}}
- // {{{ _getElementId()
-
- /**
- *
- *
- * @version 2002/01/21
- * @access private
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param int the element ID
- *
- */
- function _getElementId($id, $what)
- {
- if (isset($this->data[$id][$what]) && $this->data[$id][$what]) {
- return $this->data[$id][$what]['id'];
- }
- return null;
+ return $element;;
}
// }}}
@@ -1021,6 +889,7 @@
* @author Wolfram Kriesing <wolfram@kriesing.de>
* @param mixed either the id of an element
* or the path to the element
+ * @param string the field name
*
*/
function getElementContent($idOrPath, $fieldName)
@@ -1041,6 +910,7 @@
* @access private
* @author Wolfram Kriesing <wolfram@kriesing.de>
* @param int the element ID
+ * @param string the field name
*
*/
function getElementsContent($ids, $fieldName) {
@@ -1048,7 +918,7 @@
// Since it only serves my lazyness
// is this effective here? i can also loop in the calling code!?
$fields = array();
- if (is_array($ids) && count($ids)) {
+ if (isset($ids) && is_array($ids) && count($ids)) {
foreach ($ids as $aId) {
$fields[] = $this->getElementContent($aId, $fieldName);
}
@@ -1074,12 +944,14 @@
*/
function &getElementByPath($path, $startId = 0, $nodeName = 'name', $seperator = '/')
{
+ // null since false might be interpreted as id 0
$element = null;
- $id = $this->getIdByPath($path,$startId);
+
+ $id = $this->getIdByPath($path, $startId);
if ($id) {
- $element = &$this->getElement($id);
+ $element = &$this->_getElement($id);
}
- // return null since false might be interpreted as id 0
+
return $element;
}
@@ -1101,26 +973,6 @@
}
// }}}
- // {{{ getChild()
-
- /**
- * returns the child if the node given has one
- * !!! ATTENTION watch out that you never change any of the data returned,
- * since they are references to the internal property $data
- *
- * @version 2001/11/27
- * @access public
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param mixed the id of the node to get the child for
- *
- */
- function &getChild($id)
- {
- $element = &$this->_getElement($id, 'child');
- return $element;
- }
-
- // }}}
// {{{ getParent()
/**
@@ -1136,12 +988,12 @@
*/
function &getParent($id)
{
- $element = &$this->_getElement($id, 'parent');
+ $element = &$this->_getElement($id, 'parent_id');
return $element;
}
// }}}
- // {{{ getNext()
+ // {{{ nextSibling()
/**
* returns the next element if the node given has one
@@ -1154,14 +1006,14 @@
* @param mixed the id of the node to get the child for
* @return mixed reference to the next element or false if there is none
*/
- function &getNext($id)
+ function &nextSibling($id)
{
- $element = &$this->_getElement($id, 'next');
+ $element = &$this->_getElement($id, 'nextId');
return $element;
}
// }}}
- // {{{ getPrevious()
+ // {{{ prevSibling()
/**
* returns the previous element if the node given has one
@@ -1174,9 +1026,9 @@
* @param mixed the id of the node to get the child for
* @return mixed reference to the next element or false if there is none
*/
- function &getPrevious($id)
+ function &prevSibling($id)
{
- $element = &$this->_getElement($id, 'previous');
+ $element = &$this->_getElement($id, 'prevId');
return $element;
}
@@ -1197,8 +1049,8 @@
/*
function &getNode($id)
{
- //$element = &$this->_getElement($id);
- //return $element;
+ $element = &$this->_getElement($id);
+ return $element;
}
*/
@@ -1227,38 +1079,48 @@
{
// if no start ID is given get the root
if ($startId == 0) {
- $startId = $this->getFirstRootId();
+ $root = $this->getFirstRoot();
+ $startId = $root['id'];
} else { // if a start id is given, get its first child to start searching there
- $startId = $this->getChildId($startId);
- if ($startId==false) { // is there a child to this element?
+ $startId = $this->children[$startId][0];
+ if ($startId === false) { // is there a child to this element?
return false;
}
}
- if (strpos($path,$seperator) === 0) { // if a seperator is at the beginning strip it off
- $path = substr($path,strlen($seperator));
+ // if a seperator is at the beginning strip it off
+ if (strpos($path, $seperator) === 0) {
+ $path = substr($path, strlen($seperator));
}
+
$nodes = explode($seperator, $path);
+ $nodeCount = count($nodes);
$curId = $startId;
+
foreach ($nodes as $key => $aNodeName) {
$nodeFound = false;
do {
- if ($this->data[$curId][$nodeName] == $aNodeName) {
+ if (isset($this->data[$curId][$nodeName]) &&
+ $this->data[$curId][$nodeName] == $aNodeName
+ ) {
$nodeFound = true;
// do only save the child if we are not already at the end of path
// because then we need curId to return it
- if ($key < (count($nodes) - 1)) {
- $curId = $this->getChildId($curId);
+ if ($key < ($nodeCount - 1)) {
+ $curId = $this->children[$curId][0];
}
break;
}
- $curId = $this->getNextId($curId);
+
+ $next = $this->nextSibling($curId);
+ $curId = $next['id'];
} while($curId);
- if ($nodeFound == false) {
+ if ($nodeFound === false) {
return false;
}
}
+
return $curId;
// FIXXME to be implemented
}
@@ -1291,7 +1153,7 @@
/**
* since in a nested tree there can only be one root
* which i think (now) is correct, we also need an alias for this method
- * this also makes all the methods in Tree_Common, which access the
+ * this also makes all the methods in Tree, which access the
* root element work properly!
*
* @access public
@@ -1301,19 +1163,19 @@
*/
function &getRoot()
{
- $tmp = $this->getFirstRoot();
- return $tmp;
+ $element = &$this->getFirstRoot();
+ return $element;
}
// }}}
- // {{{ getRoot()
+ // {{{ getBranch()
/**
* gets the tree under the given element in one array, sorted
* so you can go through the elements from begin to end and list them
* as they are in the tree, where every child (until the deepest) is retreived
*
- * @see &_getNode()
+ * @see &_getBranch()
* @access public
* @version 2001/12/17
* @author Wolfram Kriesing <wolfram@kriesing.de>
@@ -1323,24 +1185,20 @@
* retreived
* @return array sorted as listed in the tree
*/
- function &getNode($startId=0, $depth=0)
+ function &getBranch($startId = 0, $depth = 0)
{
- if ($startId == 0) {
- $level = 0;
- } else {
- $level = $this->getLevel($startId);
- }
+ $level = $startId == 0 ? 0 : $this->getLevel($startId);
$this->_getNodeMaxLevel = $depth ? ($depth + $level) : 0 ;
//!!! $this->_getNodeCurParent = $this->data['parent']['id'];
// if the tree is empty dont walk through it
if (!count($this->data)) {
- $tmp = null;
- return $tmp;
+ $a = array();
+ return $a;
}
- $ret = $this->walk(array(&$this,'_getNode'), $startId, 'ifArray');
+ $ret = $this->walk(array(&$this, '_getBranch'), $startId, 'ifArray');
return $ret;
}
@@ -1351,7 +1209,7 @@
* this is used for walking through the tree structure
* until a given level, this method should only be used by getNode
*
- * @see &getNode()
+ * @see &getBranch()
* @see walk()
* @see _walk()
* @access private
@@ -1361,15 +1219,15 @@
* @return mixed either returns the node, or nothing
* if the level _getNodeMaxLevel is reached
*/
- function &_getNode(&$node)
+ function &_getBranch(&$node)
{
if ($this->_getNodeMaxLevel) {
if ($this->getLevel($node['id']) < $this->_getNodeMaxLevel) {
return $node;
}
- $tmp = null;
- return $tmp;
+ return;
}
+
return $node;
}
@@ -1382,23 +1240,32 @@
* @version 2001/12/17
* @access public
* @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param integer $id the id of the node to check for children
+ * @param integer|array $id the id of the node to check for children
+ * @param boolean if only the first child should be returned (only used when one id is passed)
* @param integer the children of how many levels shall be returned
+
* @return boolean true if the node has children
*/
- function getChildren($ids, $levels = 1)
+ function getChildren($ids, $oneChild = false, $levels = 1)
{
//FIXXME $levels to be implemented
$ret = array();
if (is_array($ids)) {
foreach ($ids as $aId) {
if ($this->hasChildren($aId)) {
- $ret[$aId] = $this->data[$aId]['children'];
+ foreach ($this->children[$aId] as $value) {
+ $ret[$aId][] = $this->data[$value];
+ }
}
}
} else {
if ($this->hasChildren($ids)) {
- $ret = $this->data[$ids]['children'];
+ foreach ($this->children[$ids] as $value) {
+ $ret[] = $this->data[$value];
+ if ($oneChild) {
+ return $ret = $ret[0];
+ }
+ }
}
}
return $ret;
@@ -1422,6 +1289,24 @@
}
// }}}
+
+ /**
+ * returns if the given element has any children
+ *
+ * @version 2001/12/17
+ * @access public
+ * @author Wolfram Kriesing <wolfram@kriesing.de>
+ * @param integer $id the id of the node to check for children
+ * @return boolean true if the node has children
+ */
+ function hasChildren($id = 0)
+ {
+ if (isset($this->children[$id])) {
+ return true;
+ }
+ return false;
+ }
+
// {{{ varDump()
/**
@@ -1445,7 +1330,7 @@
// if $node is an array, we assume it is a collection of elements
if (!is_array($node)) {
- $nodes = $this->getNode($node);
+ $nodes = $this->getBranch($node);
} else {
$nodes = $node;
}
@@ -1496,23 +1381,21 @@
*/
function copy($srcId, $destId)
{
- if (method_exists($this->dataSourceClass, 'copy')) {
- return $this->dataSourceClass->copy($srcId, $destId);
- } else {
- return $this->_throwError('method not implemented yet.', __LINE__);
+ if (method_exists($this->dataClass, 'copy')) {
+ return $this->dataClass->copy($srcId, $destId);
}
+ return Tree::raiseError('TREE_ERROR_NOT_IMPLEMENTED');
/*
remove all array elements after 'parent' since those had been created
- and remove id and set parentId and that should be it, build the tree and pass it to addNode
+ and remove id and set parent_id and that should be it, build the tree and pass it to addNode
those are the fields in one data-entry
id=>41
-parentId=>39
+parent_id=>39
name=>Java
parent=>Array
prevId=>58
previous=>Array
-childId=>77
child=>Array
nextId=>104
next=>Array
@@ -1526,4 +1409,6 @@
}
// }}}
+
}
+?>
\ No newline at end of file
Property changes on: Tree/Memory.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.34.2.3
+1.35
Index: tests/getElementTest.php
===================================================================
--- tests/getElementTest.php (.../branches/Tree_0_3_0) (revision 321102)
+++ tests/getElementTest.php (.../trunk) (revision 321102)
@@ -1,37 +1,17 @@
<?php
-//
// $Id$
-//
require_once dirname(__FILE__) . '/TreeHelper.php';
class tests_getElementTest extends TreeHelper
{
- /**
- * There was a bug when we mapped column names, especially when we mapped
- * a column to the same name as the column. We check this here too.
- *
- *
- */
function test_MemoryDBnested()
{
$tree = $this->getMemoryDBnested();
$tree->update(3, array('comment' => 'PEAR rulez'));
$tree->setup();
$actual = $tree->getElement(3);
- $this->assertEquals('PEAR rulez', $actual['comment'], 'Original:');
-
- $tree->setOption('columnNameMaps', array('comment' => 'comment'));
- $actual = $tree->getElement(3);
- $this->assertEquals('PEAR rulez', $actual['comment'], 'Map to same name:');
-
- // This doesn't work. I took a quick look to try and fix it. What
- // a mess. Considering how much I've already fixed, I just don't
- // care anymore. Marking it incomplete. --Dan
- $this->markTestIncomplete();
- $tree->setOption('columnNameMaps', array('myComment' => 'comment'));
- $actual = $tree->getElement(3);
- $this->assertEquals('PEAR rulez', $actual['myComment'], 'Map to different name:');
+ $this->assertEquals('PEAR rulez', $actual['comment']);
}
function test_MemoryMDBnested()
@@ -46,13 +26,10 @@
$actual = $tree->getElement(3);
$this->assertEquals('PEAR rulez', $actual['comment']);
- $tree->setOption('columnNameMaps', array('comment' => 'comment'));
+ $tree->setOption('fields', array('comment' => array('type' => 'text', 'name' => 'myComment')));
+ $tree->setup();
$actual = $tree->getElement(3);
$this->assertEquals('PEAR rulez', $actual['comment']);
-
- $tree->setOption('columnNameMaps', array('myComment' => 'comment'));
- $actual = $tree->getElement(3);
- $this->assertEquals('PEAR rulez', $actual['myComment']);
}
// do this for XML
@@ -61,21 +38,11 @@
// do this for DBsimple
- // do this for DynamicDBnested
+ // do this for Dynamic[M]DB[2]nested
function test_DynamicDBnested()
{
- $tree =& $this->getDynamicDBnested();
- $tree->update(3, array('comment' => 'PEAR rulez'));
- $actual = $tree->getElement(3);
- $this->assertEquals('PEAR rulez', $actual['comment']);
-
- $tree->setOption('columnNameMaps', array('comment' => 'comment'));
- $actual = $tree->getElement(3);
- $this->assertEquals('PEAR rulez', $actual['comment']);
-
- $tree->setOption('columnNameMaps', array('myComment' => 'comment'));
- $actual = $tree->getElement(3);
- $this->assertEquals('PEAR rulez', $actual['myComment']);
+ $tree =& $this->getDynamicSQLnested('DB');
+ $this->_test_DynamicSQLnested($tree);
}
function test_DynamicMDBnested()
@@ -84,18 +51,25 @@
$this->markTestSkipped('MDB is not installed');
}
- $tree =& $this->getDynamicMDBnested();
+ $tree =& $this->getDynamicSQLnested('MDB');
+ $this->_test_DynamicSQLnested($tree);
+ }
+
+ function test_DynamicMDB2nested()
+ {
+ if (!$this->has_mdb2) {
+ $this->markTestSkipped('MDB2 is not installed');
+ }
+
+ $tree =& $this->getDynamicSQLnested('MDB2');
+ $this->_test_DynamicSQLnested($tree);
+ }
+
+ function _test_DynamicSQLnested(&$tree)
+ {
$tree->update(3, array('comment' => 'PEAR rulez'));
$actual = $tree->getElement(3);
$this->assertEquals('PEAR rulez', $actual['comment']);
-
- $tree->setOption('columnNameMaps', array('comment' => 'comment'));
- $actual = $tree->getElement(3);
- $this->assertEquals('PEAR rulez', $actual['comment']);
-
- $tree->setOption('columnNameMaps', array('myComment' => 'comment'));
- $actual = $tree->getElement(3);
- $this->assertEquals('PEAR rulez', $actual['myComment']);
}
/**
@@ -103,48 +77,43 @@
*
*
*/
- function test_DynamicDBnestedEmptyTree()
+ function test_DynamicSQLnestedEmptyTree()
{
- $tree = Tree::setup('Dynamic_DBnested', $this->dsn, array('table' => TABLE_TREENESTED));
- $tree->remove($tree->getRootId());
-
- $tree = Tree::setup('Memory_DBnested', $this->dsn, array('table' => TABLE_TREENESTED));
- $tree->setup();
- $id = $tree->add(array('name' => 'Start'));
- $tree->setup();
- $el = $tree->getElement($id);
- $this->assertEquals('Start', $el['name']);
- $tree->remove($tree->getRootId());
-
- $tree = Tree::setup('Dynamic_DBnested', $this->dsn, array('table' => TABLE_TREENESTED));
- $id = $tree->add(array('name' => 'StartDyn'));
- $el = $tree->getElement($id);
- $this->assertEquals('StartDyn', $el['name']);
- }
+ $config = array(
+ 'container' => 'Dynamic',
+ 'type' => 'Nested',
+ 'storage' => array(
+ 'name' => 'DB',
+ 'dsn' => $this->dsn,
+ // 'connection' =>
+ ),
+ 'options' => array(
+ 'table' => TABLE_TREENESTED,
+ 'order' => 'id',
+ 'fields' => array(),
+ ),
+ );
- function test_DynamicMDBnestedEmptyTree()
- {
- if (!$this->has_mdb) {
- $this->markTestSkipped('MDB is not installed');
- }
+ $tree = Tree::factory($config);
+ $root = $tree->getRoot();
+ $tree->remove($root['id']);
- $tree = Tree::setup('Dynamic_MDBnested', $this->dsn, array('table' => TABLE_TREENESTED));
- $tree->remove($tree->getRootId());
-
- $tree = Tree::setup('Memory_MDBnested', $this->dsn, array('table' => TABLE_TREENESTED));
+ $config['container'] = 'Memory';
+ $tree = Tree::factory($config);
$tree->setup();
$id = $tree->add(array('name' => 'Start'));
$tree->setup();
$el = $tree->getElement($id);
$this->assertEquals('Start', $el['name']);
- $tree->remove($tree->getRootId());
-
- $tree = Tree::setup('Dynamic_MDBnested', $this->dsn, array('table' => TABLE_TREENESTED));
+ $root = $tree->getRoot();
+ $tree->remove($root['id']);
+
+ $config['container'] = 'Dynamic';
+ $tree = Tree::factory($config);
$id = $tree->add(array('name' => 'StartDyn'));
$el = $tree->getElement($id);
$this->assertEquals('StartDyn', $el['name']);
- }
-
+ }
}
?>
Property changes on: tests/getElementTest.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.3
+1.4
Index: tests/getPathTest.php
===================================================================
--- tests/getPathTest.php (.../branches/Tree_0_3_0) (revision 321102)
+++ tests/getPathTest.php (.../trunk) (revision 321102)
@@ -1,7 +1,5 @@
<?php
-//
// $Id$
-//
require_once dirname(__FILE__) . '/TreeHelper.php';
@@ -30,29 +28,19 @@
// do this for DBsimple
- // do this for DynamicDBnested
- function test_DynamicDBnested()
+ // do this for DynamicSQLnested
+ function test_DynamicSQLnested()
{
- $tree =& $this->getDynamicDBnested();
+ $tree =& $this->getDynamicSQLnested();
$this->_testPath($tree);
}
-
- function test_DynamicMDBnested()
- {
- if (!$this->has_mdb) {
- $this->markTestSkipped('MDB is not installed');
- }
-
- $tree =& $this->getDynamicMDBnested();
- $this->_testPath($tree);
- }
function _testPath(&$tree)
{
// $id = $tree->getIdByPath('/Root/child 2/child 2_2');
$id = 5;
$path = $tree->getPath($id);
-
+
$this->assertEquals(3, sizeof($path));
$this->assertEquals('Root', $path[0]['name']);
$this->assertEquals('child 2', $path[1]['name']);
Property changes on: tests/getPathTest.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.2
+1.3
Index: tests/removeTest.php
===================================================================
--- tests/removeTest.php (.../branches/Tree_0_3_0) (revision 321102)
+++ tests/removeTest.php (.../trunk) (revision 321102)
@@ -1,7 +1,5 @@
<?php
-//
// $Id$
-//
require_once dirname(__FILE__) . '/TreeHelper.php';
@@ -31,7 +29,7 @@
{
$tree = $this->getMemoryDBnested();
// $id = $tree->getIdByPath('/Root/child 2/child 2_2');
- $parentId = $tree->getParentId(5);
+ $parent = $tree->getParent(5);
$ret = $tree->move(5, 5);
$tree->setup();
@@ -42,7 +40,8 @@
$this->fail('Expected TRUE but got a ' . gettype($ret));
}
- $this->assertEquals($parentId, $tree->getParentId(5));
+ $parent1 = $tree->getParent(5);
+ $this->assertEquals($parent['id'], $parent1['id']);
}
function test_MemoryMDBnestedNoAction()
@@ -53,7 +52,7 @@
$tree = $this->getMemoryMDBnested();
// $id = $tree->getIdByPath('/Root/child 2/child 2_2');
- $parentId = $tree->getParentId(5);
+ $parent = $tree->getParent(5);
$ret = $tree->move(5, 5);
$tree->setup();
@@ -64,7 +63,8 @@
$this->fail('Expected TRUE but got a ' . gettype($ret));
}
- $this->assertEquals($parentId, $tree->getParentId(5));
+ $parent1 = $tree->getParent(5);
+ $this->assertEquals($parent['id'], $parent1['id']);
}
// do this for XML
@@ -73,10 +73,10 @@
// do this for DBsimple
- // do this for DynamicDBnested
- function test_DynamicDBnested()
+ // do this for DynamicSQLnested
+ function test_DynamicSQLnested()
{
- $tree =& $this->getDynamicDBnested();
+ $tree =& $this->getDynamicSQLnested();
$ret = $tree->remove(5);
// Avoid PHPUnit exhausting memory if $ret is a large array or object.
@@ -96,33 +96,6 @@
$this->fail('Expected TRUE but got a ' . gettype($ret));
}
}
-
- function test_DynamicMDBnested()
- {
- if (!$this->has_mdb) {
- $this->markTestSkipped('MDB is not installed');
- }
-
- $tree =& $this->getDynamicMDBnested();
- $ret = $tree->remove(5);
-
- // Avoid PHPUnit exhausting memory if $ret is a large array or object.
- if (is_bool($ret)) {
- $this->assertTrue($ret);
- } else {
- $this->fail('Expected TRUE but got a ' . gettype($ret));
- }
-
- // and check if the element doesnt exist anymore ... this is not 100% sure, sicne the
- // returned error message is a string :-(
- // Avoid PHPUnit exhausting memory if $ret is a large array or object.
- $ret = Tree::isError($tree->getElement(5));
- if (is_bool($ret)) {
- $this->assertTrue($ret);
- } else {
- $this->fail('Expected TRUE but got a ' . gettype($ret));
- }
- }
}
?>
Property changes on: tests/removeTest.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.3.2.1
+1.4
Index: tests/TreeHelper.php
===================================================================
--- tests/TreeHelper.php (.../branches/Tree_0_3_0) (revision 321102)
+++ tests/TreeHelper.php (.../trunk) (revision 321102)
@@ -1,7 +1,5 @@
<?php
-//
// $Id$
-//
if (!defined('TABLE_TREENESTED')) {
if ($fp = @fopen('PHPUnit/Autoload.php', 'r', true)) {
@@ -59,8 +57,8 @@
function setUp()
{
- // common setup, setup the table structure and data in the db
- // (this actually also does the tearDown, since we have the DROP TABLE queries in the setup too
+ // common factory, factory the table structure and data in the db
+ // (this actually also does the tearDown, since we have the DROP TABLE queries in the factory too
require 'sql.php';
$this->dsn = unserialize(DB_DSN);
$db = DB::connect($this->dsn);
@@ -107,30 +105,72 @@
function &getMemoryDBnested()
{
- $tree = Tree::setup('Memory_DBnested', $this->dsn, array('table' => TABLE_TREENESTED));
+ $config = array(
+ 'container' => 'Memory',
+ 'type' => 'Nested',
+ 'storage' => array(
+ 'name' => 'DB',
+ 'dsn' => $this->dsn,
+ // 'connection' =>
+ ),
+ 'options' => array(
+ 'table' => TABLE_TREENESTED,
+ 'order' => 'id',
+ 'fields' => array(
+ 'comment' => array('type' => 'text', 'name' => 'comment'),
+ ),
+ ),
+ );
+ $tree = Tree::factory($config);
$tree->setup();
return $tree;
}
- function &getDynamicDBnested()
+ function &getDynamicSQLnested($name = 'DB')
{
- $tree = Tree::setup('Dynamic_DBnested', $this->dsn, array('table' => TABLE_TREENESTED));
+ $config = array(
+ 'container' => 'Dynamic',
+ 'type' => 'Nested',
+ 'storage' => array(
+ 'name' => $name,
+ 'dsn' => $this->dsn,
+ // 'connection' =>
+ ),
+ 'options' => array(
+ 'table' => TABLE_TREENESTED,
+ 'order' => 'id',
+ 'fields' => array(
+ 'comment' => array('type' => 'text', 'name' => 'comment'),
+ ),
+ ),
+ );
+ $tree = Tree::factory($config);
+
return $tree;
}
function &getMemoryMDBnested()
{
- $tree = Tree::setup('Memory_MDBnested', $this->dsn, array('table' => TABLE_TREENESTED));
+ $config = array(
+ 'container' => 'Memory',
+ 'type' => 'Nested',
+ 'storage' => array(
+ 'name' => 'MDB',
+ 'dsn' => $this->dsn,
+ // 'connection' =>
+ ),
+ 'options' => array(
+ 'table' => TABLE_TREENESTED,
+ 'order' => 'id',
+ 'fields' => array(
+ 'comment' => array('type' => 'text', 'name' => 'comment'),
+ ),
+ ),
+ );
+ $tree = Tree::factory($config);
$tree->setup();
return $tree;
}
-
- function &getDynamicMDBnested()
- {
- $tree = Tree::setup('Dynamic_MDBnested', $this->dsn, array('table' => TABLE_TREENESTED));
- return $tree;
- }
-
}
?>
Property changes on: tests/TreeHelper.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.3
+1.4
Index: tests/sql.php
===================================================================
--- tests/sql.php (.../branches/Tree_0_3_0) (revision 321102)
+++ tests/sql.php (.../trunk) (revision 321102)
Property changes on: tests/sql.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.1
+1.2
Index: tests/getIdByPathTest.php
===================================================================
--- tests/getIdByPathTest.php (.../branches/Tree_0_3_0) (revision 321102)
+++ tests/getIdByPathTest.php (.../trunk) (revision 321102)
@@ -1,7 +1,5 @@
<?php
-//
// $Id$
-//
require_once dirname(__FILE__) . '/TreeHelper.php';
@@ -10,9 +8,9 @@
// check if we get the right ID, for the given path
function test_MemoryDBnested()
{
- $tree = $this->getMemoryDBnested();
- $id = $tree->getIdByPath('/Root/child 2/child 2_2');
-
+ $tree = $this->getMemoryDBnested();
+ $id = $tree->getIdByPath('Root/child 2/child 2_2');
+
$this->assertEquals(5, $id);
}
@@ -22,8 +20,8 @@
$this->markTestSkipped('MDB is not installed');
}
- $tree = $this->getMemoryMDBnested();
- $id = $tree->getIdByPath('/Root/child 2/child 2_2');
+ $tree = $this->getMemoryMDBnested();
+ $id = $tree->getIdByPath('Root/child 2/child 2_2');
$this->assertEquals(5, $id);
}
@@ -34,27 +32,16 @@
// do this for DBsimple
- // do this for DynamicDBnested
- function test_DynamicDBnested()
+ // do this for DynamicSQLnested
+ function test_DynamicSQLnested()
{
- $tree = $this->getDynamicDBnested();
+ $tree = $this->getDynamicSQLnested();
$id = $tree->getIdByPath('/Root/child 2/child 2_2');
- $this->assertEquals(5, $id,'This is not implemented, yet!!! (This test should fail ... for now)');
- }
-
- function test_DynamicMDBnested()
- {
- if (!$this->has_mdb) {
- $this->markTestSkipped('MDB is not installed');
- }
+ $this->markTestIncomplete();
- $tree = $this->getDynamicMDBnested();
- $id = $tree->getIdByPath('/Root/child 2/child 2_2');
-
- $this->assertEquals(5, $id,'This is not implemented, yet!!! (This test should fail ... for now)');
+ $this->assertEquals(5, $id, 'This is not implemented, yet!!! (This test should fail ... for now)');
}
-
}
?>
Property changes on: tests/getIdByPathTest.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.3
+1.4
Index: tests/moveTest.php
===================================================================
--- tests/moveTest.php (.../branches/Tree_0_3_0) (revision 321102)
+++ tests/moveTest.php (.../trunk) (revision 321102)
@@ -1,7 +1,5 @@
<?php
-//
// $Id$
-//
require_once dirname(__FILE__) . '/TreeHelper.php';
@@ -22,7 +20,8 @@
}
// and check if the move succeeded, by checking the new parentId
- $this->assertEquals(1,$tree->getParentId(5));
+ $parent = $tree->getParent(5);
+ $this->assertEquals(1, $parent['id']);
}
function test_MemoryMDBnested()
@@ -43,14 +42,15 @@
}
// and check if the move succeeded, by checking the new parentId
- $this->assertEquals(1, $tree->getParentId(5));
+ $parent = $tree->getParent(5);
+ $this->assertEquals(1, $parent['id']);
}
function test_MemoryDBnestedNoAction()
{
$tree = $this->getMemoryDBnested();
// $id = $tree->getIdByPath('/Root/child 2/child 2_2');
- $parentId = $tree->getParentId(5);
+ $parent = $tree->getParent(5);
$ret = $tree->move(5, 5);
$tree->setup();
@@ -61,7 +61,8 @@
$this->fail('Expected TRUE but got a ' . gettype($ret));
}
- $this->assertEquals($parentId, $tree->getParentId(5));
+ $parent1 = $tree->getParent(5);
+ $this->assertEquals($parent['id'], $parent1['id']);
}
function test_MemoryMDBnestedNoAction()
@@ -72,7 +73,7 @@
$tree = $this->getMemoryMDBnested();
// $id = $tree->getIdByPath('/Root/child 2/child 2_2');
- $parentId = $tree->getParentId(5);
+ $parent = $tree->getParent(5);
$ret = $tree->move(5, 5);
$tree->setup();
@@ -83,7 +84,8 @@
$this->fail('Expected TRUE but got a ' . gettype($ret));
}
- $this->assertEquals($parentId, $tree->getParentId(5));
+ $parent1 = $tree->getParent(5);
+ $this->assertEquals($parent['id'], $parent1['id']);
}
// do this for XML
@@ -92,10 +94,10 @@
// do this for DBsimple
- // do this for DynamicDBnested
- function test_DynamicDBnested()
+ // do this for DynamicSQLnested
+ function test_DynamicSQLnested()
{
- $tree =& $this->getDynamicDBnested();
+ $tree =& $this->getDynamicSQLnested();
$ret = $tree->move(5, 1);
// Avoid PHPUnit exhausting memory if $ret is a large array or object.
@@ -106,34 +108,15 @@
}
// and check if the move succeeded, by checking the new parentId
- $this->assertEquals(1, $tree->getParentId(5));
+ $parent = $tree->getParent(5);
+ $this->assertEquals(1, $parent['id']);
}
- function test_DynamicMDBnested()
+ function test_DynamicSQLnestedNoAction()
{
- if (!$this->has_mdb) {
- $this->markTestSkipped('MDB is not installed');
- }
-
- $tree =& $this->getDynamicDBnested();
- $ret = $tree->move(5, 1);
-
- // Avoid PHPUnit exhausting memory if $ret is a large array or object.
- if (is_bool($ret)) {
- $this->assertTrue($ret);
- } else {
- $this->fail('Expected TRUE but got a ' . gettype($ret));
- }
-
- // and check if the move succeeded, by checking the new parentId
- $this->assertEquals(1, $tree->getParentId(5));
- }
-
- function test_DynamicDBnestedNoAction()
- {
- $tree =& $this->getDynamicDBnested();
+ $tree =& $this->getDynamicSQLnested();
// $id = $tree->getIdByPath('/Root/child 2/child 2_2');
- $parentId = $tree->getParentId(5);
+ $parent = $tree->getParent(5);
$ret = $tree->move(5, 5);
// Avoid PHPUnit exhausting memory if $ret is a large array or object.
@@ -143,29 +126,9 @@
$this->fail('Expected TRUE but got a ' . gettype($ret));
}
- $this->assertEquals($parentId, $tree->getParentId(5));
- }
-
- function test_DynamicMDBnestedNoAction()
- {
- if (!$this->has_mdb) {
- $this->markTestSkipped('MDB is not installed');
- }
-
- $tree =& $this->getDynamicMDBnested();
-// $id = $tree->getIdByPath('/Root/child 2/child 2_2');
- $parentId = $tree->getParentId(5);
- $ret = $tree->move(5, 5);
-
- // Avoid PHPUnit exhausting memory if $ret is a large array or object.
- if (is_bool($ret)) {
- $this->assertTrue($ret);
- } else {
- $this->fail('Expected TRUE but got a ' . gettype($ret));
- }
-
- $this->assertEquals($parentId, $tree->getParentId(5));
- }
+ $parent1 = $tree->getParent(5);
+ $this->assertEquals($parent['id'], $parent1['id']);
+ }
}
?>
Property changes on: tests/moveTest.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.2
+1.3
Index: tests/getLevelTest.php
===================================================================
--- tests/getLevelTest.php (.../branches/Tree_0_3_0) (revision 321102)
+++ tests/getLevelTest.php (.../trunk) (revision 321102)
@@ -1,7 +1,5 @@
<?php
-//
// $Id$
-//
require_once dirname(__FILE__) . '/TreeHelper.php';
@@ -21,7 +19,7 @@
$this->markTestSkipped('MDB is not installed');
}
- $tree = $this->getMemoryMDBnested();
+ $tree = $this->getMemoryMDBnested();
$id = $tree->getIdByPath('/Root/child 2/child 2_2');
$this->assertEquals(2, $tree->getLevel($id));
}
@@ -32,26 +30,14 @@
// do this for DBsimple
- // do this for DynamicDBnested
- function test_DynamicDBnested()
+ // do this for DynamicSQLnested
+ function test_DynamicSQLnested()
{
- $tree =& $this->getDynamicDBnested();
+ $tree =& $this->getDynamicSQLnested();
// $id = $tree->getIdByPath('/Root/child 2/child 2_2');
$id = 5;
$this->assertEquals(2, $tree->getLevel($id));
}
-
- function test_DynamicMDBnested()
- {
- if (!$this->has_mdb) {
- $this->markTestSkipped('MDB is not installed');
- }
-
- $tree =& $this->getDynamicMDBnested();
-// $id = $tree->getIdByPath('/Root/child 2/child 2_2');
- $id = 5;
- $this->assertEquals(2, $tree->getLevel($id));
- }
}
?>
Property changes on: tests/getLevelTest.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.2
+1.3
Index: tests
===================================================================
--- tests (.../branches/Tree_0_3_0) (revision 321102)
+++ tests (.../trunk) (revision 321102)
Property changes on: tests
___________________________________________________________________
Added: svn:ignore
## -0,0 +1 ##
+.getElementTest.php.swp
Index: TODO
===================================================================
--- TODO (.../branches/Tree_0_3_0) (revision 321102)
+++ TODO (.../trunk) (revision 321102)
@@ -4,10 +4,52 @@
use cached results. i.e. when calling getElement(2) three times, normally it would read
the data from the DB 3 times, but with a cache it could use cached results.
of course not cached permanently only for the current script life time
-- about Cache, add a per "transaction" cache. That means, when the users call a complex
+- about Cache, add a per "transaction" cache. That means, when the users call a complex
method (getIdByPath), cache the result during the read "transaction", lock?
-- setOption('columnNameMaps') doesnt work i.e. here
- $tree->setOption('columnNameMaps',array('myComment'=>'comment'));
- $tree->setOption('columnNameMaps',array('comment'=>'comment'));
- because we dont have the column name as the array key, so we cant overwrite it :-(
- this is really stupid
+
+ http://www.phpguru.org/Tree2/
+ * http://www.phpguru.org/article.php?ne_id=18
+ http://cvs.iworks.at/cvs.php/Tree
+ http://wiki.iworks.at/index.php?area=Tree&page=HomePage
+ http://cvs.iworks.at/cvs.php/Gadget/Tree?login=2&rt=Gadget
+ Move to another architecture, talk to Mike and Lorenzo about joining in.
+
+- Remove nodes recrusivly always.
+- Do not require the whole setup process after add/edit/remove/move/copy in memory
+ note sure tho what to do with memory <-> dynamic
+- because I removed things like parent, next, previous and such fromt the $data array
+ then I must fix _getElementId(removed) to cope with that and every other function related to this
+- Find a better way to deal with getParent and such when there is no result
+- remove buildStructure and add the level code to were I make the structure now and unset parent_id also in the data array
+- Add Transactions
+- New storage container approach
+- setData in all containers
+- Fully implement Array container
+- Fix structure thing, walk is having some issue, doesn't give errors anymore but there are issues
+- Fix getChildren
+- Enhance getAllChildren[ids]
+- Implement levels to getChildren
+- Reimplement get*Id and remove get* and have only one getNode or getData or what ever
+
+Profile this whole thing with APD when I get it to work or xdebug
+
+
+Open your favourite browser,
+and google for "joe celko" and "nested set"
+
+http://www.intelligententerprise.com/001020/celko.jhtml?_requestid=27476
+http://www.dbmsmag.com/9603d06.html
+http://www.dbmsmag.com/9604d06.html
+http://www.ibase.ru/devinfo/DBMSTrees/sqltrees.html
+
+Suggested books (both of them are excellent):
+http://www.amazon.com/exec/obidos/ASIN/0262032937/
+http://www.amazon.com/exec/obidos/ASIN/1558609202/
+
+
+http://www.msci.memphis.edu/~giri/7713/f99/l2/dferebee.htm
+
+Good naming thign http://www.cross-browser.com/cbe/docs/core_om.html
+
+http://www.entwickler.com/itr/online_artikel/psecom,id,387,nodeid,114.html
+file:///home/dufuz/Desktop/traer.html
Property changes on: TODO
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.3
+1.4
Index: docs/Dynamic_DBnested.php
===================================================================
--- docs/Dynamic_DBnested.php (.../branches/Tree_0_3_0) (revision 321102)
+++ docs/Dynamic_DBnested.php (.../trunk) (revision 321102)
@@ -1,51 +1,87 @@
<?php
- //
- // $Id$
- //
+// $Id$
-//ini_set('include_path',realpath(dirname(__FILE__).'/../../').':'.realpath(dirname(__FILE__).'/../../../includes').':'.ini_get('include_path'));
+// use nested_tree.sql to build the db table
+
ini_set('error_reporting', E_ALL);
- require_once 'Tree/Tree.php';
+require_once 'Benchmark/Timer.php';
+$timer = new Benchmark_Timer();
+$timer->start();
-# $tree = Tree::setupDynamic('DBnested' , 'mysql://root@localhost/tree_test' , array('table' => 'nestedTree'));
-# OR
- $tree = Tree::setup('Dynamic_DBnested' , 'mysql://root@localhost/tree_test' , array('table' => 'nestedTree'));
+require_once 'Tree/Tree.php';
- $show[] = '$tree->getRoot()';
- $show[] = '$tree->getElement(1)';
- $show[] = '$tree->getChild(1)';
- $show[] = '$tree->getPath(7)';
- $show[] = '$tree->getPath(2)';
- $show[] = '$tree->add(array("name"=>"c0") , 5 )';
- $show[] = '$tree->remove( $res )'; // remove the last element that was added in the line before :-)
- $show[] = '$tree->getRight( 5 )';
- $show[] = '$tree->getLeft( 5 )';
- $show[] = '$tree->getChildren( 1 )';
- $show[] = '$tree->getParent( 2 )';
- $show[] = '$tree->getNext( 2 )';
- $show[] = '$tree->getNext( 4 )';
- $show[] = '$tree->getNext( 8 )';
- $show[] = '$tree->getPrevious( 2 )';
- $show[] = '$tree->getPrevious( 4 )';
- $show[] = '$tree->getPrevious( 8 )';
- $show[] = '$tree->getPreviousId( 8 )';
+$config = array(
+ 'type' => 'Nested',
+ 'storage' => array(
+ 'name' => 'DB',
+ 'dsn' => 'mysql://root:hamstur@localhost/tree_test',
+ // 'connection' =>
+ ),
+ 'options' => array(
+ 'table' => 'nestedTree',
+ 'order' => 'id',
+ 'fields' => array(),
+ ),
+);
- $show[] = '$tree->move( 4,3 )';
+$tree =& Tree::factoryDynamic($config);
+$show[] = '$tree->getRoot()';
+$show[] = '$tree->getElement(1)';
+$show[] = '$tree->getChildren(1, true)';
+$show[] = '$tree->getPath(7)';
+$show[] = '$tree->getPath(2)';
+$show[] = '$tree->add(array("name"=>"c0") , 5 )';
+$show[] = '$tree->remove( $res )'; // remove the last element that was added in the line before :-)
+$show[] = '$tree->getRight( 5 )';
+$show[] = '$tree->getLeft( 5 )';
+$show[] = '$tree->getChildren( 1 )';
+$show[] = '$tree->getParent( 2 )';
+$show[] = '$tree->nextSibling( 2 )';
+$show[] = '$tree->nextSibling( 4 )';
+$show[] = '$tree->nextSibling( 8 )';
+$show[] = '$tree->previousSibling( 2 )';
+$show[] = '$tree->previousSibling( 4 )';
+$show[] = '$tree->previousSibling( 8 )';
- foreach($show as $aRes) {
- echo "<b>$aRes</b><br>";
- eval("\$res=".$aRes.';');
- if ($res == false) {
- print "false";
- } else {
- print_r($res);
- }
- echo '<br><br>';
+$show[] = '$tree->move( 4,3 )';
+
+
+foreach ($show as $aRes) {
+ echo "<strong>$aRes</strong><br />";
+ eval("\$res=".$aRes.';');
+ if ($res == false) {
+ print "false";
+ } else {
+ echo '<pre>';
+ print_r($res);
+ echo '</pre>';
}
+ echo '<br /><br />';
+}
+$timer->stop();
+$timer->display();
+$timer = new Benchmark_Timer();
+$timer->start();
+
+$root = $tree->getRoot();
+recursive($root['id']);
+
+$timer->stop();
+$timer->display();
+
+function recursive($id)
+{
+ global $tree;
+ $blah = $tree->getChildren($id);
+ foreach ($blah as $row) {
+ echo str_repeat('-', $tree->getLevel($row['id']) - 1) . $row['id'].'<br />';
+ recursive($row['id']);
+ }
+}
?>
<a href="http://research.calacademy.org/taf/proceedings/ballew/sld029.htm">the tree structure visualisation</a>
Property changes on: docs/Dynamic_DBnested.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.3
+1.4
Index: docs/Memory_MDBnested.php
===================================================================
--- docs/Memory_MDBnested.php (.../branches/Tree_0_3_0) (revision 321102)
+++ docs/Memory_MDBnested.php (.../trunk) (revision 321102)
@@ -1,58 +1,14 @@
<?php
// $Id$
-ini_set('error_reporting',E_ALL);
+include_once 'funcs.php';
- /**
- * this is a helper function, so i dont have to write so many prints :-)
- * @param array $para the result returned by some method, that will be dumped
- * @param string $string the explaining string
- */
- function dumpHelper($para, $string = '', $addArray = false)
- {
- global $tree, $element;
- if ($addArray) {
- eval( "\$res=array(".$para.');' );
- } else {
- eval( "\$res=".$para.';' );
- }
- echo '<b>'.$para.' </b><i><u><span style="color: #008000">'.$string.'</span></u></i><br />';
- // this method dumps to the screen, since print_r or var_dump dont
- // work too good here, because the inner array is recursive
- // well, it looks ugly but one can see what is meant :-)
- $tree->varDump($res);
- echo '<br />';
-
- }
-
- /**
- * dumps the entire structure nicely
- * @param string $string the explaining string
- */
- function dumpAllNicely($string = '')
- {
- global $tree;
-
- echo '<i><u><span style="color: #008000">'.$string.'</span></u></i><br />';
- $all = $tree->getNode(); // get the entire structure sorted as the tree is, so we can simply foreach through it and show it
- foreach($all as $aElement) {
- for ($i = 0; $i < $aElement['level']; $i++) {
- echo '&nbsp; &nbsp; ';
- }
- echo '<span style="color: red">'.$aElement['name'].'</span> ===&gt; ';
- $tree->varDump(array($aElement));
- }
- echo '<br />';
-
- }
-
-
/*
use this to build the db table
- CREATE TABLE Memory_Nested_MDB (
+ CREATE TABLE Memory_nestedTree (
id int(11) NOT NULL default '0',
name varchar(255) NOT NULL default '',
l int(11) NOT NULL default '0',
@@ -62,7 +18,6 @@
PRIMARY KEY (id)
);
-
This example demonstrates how to manage trees
that are saved in a DB, it uses a very simple
DB-structure, not nested trees (ok, that sucks, but it can be implemented :-) )
@@ -78,10 +33,6 @@
require_once 'Tree/Tree.php';
// define the DB-table where the data shall be read from
- $options = array('table' => 'Memory_Nested_MDB'
- ,'whereAddOn' => "comment=''"
- );
-
// calling 'setupMemory' means to retreive a class, which works on trees,
// that are temporarily stored in the memory, in an array
// this means the entire tree is available at all time !!!
@@ -92,10 +43,23 @@
// use the nested DB schema, which is actually implemented in Dynamic/DBnested
// the class Memory/DBnested is only kind of a wrapper to read the entire tree
// and let u work on it, which to use should be chosen on case by case basis
- $tree = Tree::setupMemory('MDBnested',
- 'mysql://root@localhost/tree_test', // the DSN
- $options); // pass the options we had assigned up there
+$config = array(
+ 'type' => 'Nested',
+ 'storage' => array(
+ 'name' => 'MDB',
+ 'dsn' => 'mysql://root:hamstur@localhost/tree_test',
+ // 'connection' =>
+ ),
+ 'options' => array(
+ 'table' => 'nestedTree',
+ 'order' => 'id',
+ 'fields' => array(),
+ 'whereAddOn' => "comment=''"
+ ),
+);
+$tree =& Tree::factoryMemory($config); // pass the options we had assigned up there
+
// add a new root element in the tree
$rootId = $tree->add(array('name' => 'myElement'));
@@ -119,7 +83,7 @@
// you can also use: $tree->data[$id]['parent']
$id = $tree->getIdByPath('myElement');
- dumpHelper('$tree->getChild('.$id.')' , 'dump the child of "myElement"' , true);
+ dumpHelper('$tree->getChildren('.$id.', true)' , 'dump the child of "myElement"' , true);
// you can also use: $tree->data[$id]['child']
$id = $tree->getIdByPath('myElement');
@@ -127,11 +91,11 @@
// you can also use: $tree->data[$id]['children']
$id = $tree->getIdByPath('myElement/subElement');
- dumpHelper('$tree->getNext('.$id.')' , 'dump the "next" of "myElement/subElement"' , true);
+ dumpHelper('$tree->nextSibling('.$id.')' , 'dump the "next" of "myElement/subElement"' , true);
// you can also use: $tree->data[$id]['next']
$id = $tree->getIdByPath('myElement/anotherSubElement');
- dumpHelper('$tree->getPrevious('.$id.')' , 'dump the "previous" of "myElement/anotherSubElement"' , true);
+ dumpHelper('$tree->previousSibling('.$id.')' , 'dump the "previous" of "myElement/anotherSubElement"' , true);
// you can also use: $tree->data[$id]['previous']
$id = $tree->getIdByPath('myElement');
@@ -141,18 +105,18 @@
$id = $tree->getIdByPath('myElement');
$element = $tree->data[$id]['child']['next']; // refer to the second child of 'myElement'
dumpHelper('$element[\'id\']' , 'demo2 of using the internal array, for referencing tree-nodes, see the code');
-/*
+
$id = $tree->getIdByPath('myElement/anotherSubElement');
- $tree->move( $id , 0 );
+ $tree->move($id , 0);
$tree->setup(); // rebuild the structure again, since we had changed it
dumpAllNicely( 'dump all, after "myElement/anotherSubElement" was moved under the root' );
$moveId = $tree->getIdByPath('myElement');
$id = $tree->getIdByPath('anotherSubElement');
- $tree->move( $moveId , $id );
+ $tree->move($moveId , $id);
$tree->setup(); // rebuild the structure again, since we had changed it
dumpAllNicely( 'dump all, after "myElement" was moved under the "anotherSubElement"' );
-*/
+
$tree->setRemoveRecursively(true);
$tree->remove($rootId);
echo '<span style="color: red">ALL ELEMENTS HAVE BEEN REMOVED (uncomment this part to keep them in the DB after running this test script)</span>';
Property changes on: docs/Memory_MDBnested.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.1
+1.2
Index: docs/doc.sxw
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: docs/doc.sxw
===================================================================
--- docs/doc.sxw (.../branches/Tree_0_3_0) (revision 321102)
+++ docs/doc.sxw (.../trunk) (revision 321102)
Property changes on: docs/doc.sxw
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.1
+1.2
Index: docs/Memory_MDBsimple.php
===================================================================
--- docs/Memory_MDBsimple.php (.../branches/Tree_0_3_0) (revision 321102)
+++ docs/Memory_MDBsimple.php (.../trunk) (revision 321102)
@@ -1,63 +1,16 @@
<?php
- //
- // $Id$
- //
+// $Id$
-//ini_set('include_path',realpath(dirname(__FILE__).'/../../').':'.realpath(dirname(__FILE__).'/../../../includes').':'.ini_get('include_path'));
-//ini_set('error_reporting',E_ALL);
+include_once 'funcs.php';
- /**
- * this is a helper function, so i dont have to write so many prints :-)
- * @param array $para the result returned by some method, that will be dumped
- * @param string $string the explaining string
- */
- function dumpHelper($para, $string = '', $addArray = false)
- {
- global $tree,$element;
- if ($addArray) {
- eval("\$res=array(".$para.');');
- } else {
- eval("\$res=".$para.';');
- }
- echo '<b>' . $para . ' </b><i><u><font color="#008000">' . $string . '</font></u></i><br>';
- // this method dumps to the screen, since print_r or var_dump dont
- // work too good here, because the inner array is recursive
- // well, it looks ugly but one can see what is meant :-)
- $tree->varDump($res);
- echo '<br>';
-
- }
-
- /**
- * dumps the entire structure nicely
- * @param string $string the explaining string
- */
- function dumpAllNicely($string = '')
- {
- global $tree;
-
- echo '<i><u><font color="#008000">' . $string . '</font></u></i><br>';
- $all = $tree->getNode(); // get the entire structure sorted as the tree is, so we can simply foreach through it and show it
- foreach($all as $aElement) {
- for ($i = 0; $i < $aElement['level']; $i++) {
- echo '&nbsp; &nbsp; ';
- }
- echo $aElement['name'].' ===&gt; ';
- $tree->varDump(array($aElement));
- }
- echo '<br>';
-
- }
-
-
/*
use this to build the db table
CREATE TABLE test_tree (
id int(11) NOT NULL auto_increment,
- parentId int(11) NOT NULL default '0',
+ parent int(11) NOT NULL default '0',
name varchar(255) NOT NULL default '',
PRIMARY KEY (id)
)
@@ -74,39 +27,71 @@
i will try to demonstrate (all of) them
*/
+ require_once 'MDB.php';
+ require_once 'Benchmark/Timer.php';
+ $timer = new Benchmark_Timer();
+ $timer->start();
+
require_once 'Tree/Tree.php';
// define the DB-table where the data shall be read from
- $options = array('table' => 'test_tree',
- 'order' => 'id' // when reading the data from the db sort them by id, this is only for ensuring
- // for 'getNext' of "myElement/subElement" in this example to find "myElement/anotherSubElement"
- // you can simply sort it by "name" and it would be in alphabetical order
- );
-
+ // when reading the data from the db sort them by id, this is only for ensuring
+ // for 'getNext' of "myElement/subElement" in this example to find "myElement/anotherSubElement"
+ // you can simply sort it by "name" and it would be in alphabetical order
// calling 'setupMemory' means to retreive a class, which works on trees,
// that are temporarily stored in the memory, in an array
// this means the entire tree is available at all time
// consider the resource usage and it's not to suggested to work
// on huge trees (upto 1000 elements it should be ok, depending on your environment and requirements)
// using 'setupMemory'
- $tree = Tree::setupMemory('DBsimple', // use the simple DB schema
- 'mysql://root@localhost/tree_test', // the DSN
- $options); // pass the options we had assigned up there
+ $config = array(
+ 'type' => 'Simple',
+ 'storage' => array(
+ 'name' => 'MDB2',
+ 'dsn' => 'mysql://root:hamstur@localhost/tree_test',
+ // 'connection' => $db
+ ),
+ 'options' => array(
+ 'table' => 'test_tree',
+ 'order' => 'id',
+ 'fields' => array(),
+ ),
+ );
+ $tree =& Tree::factoryMemory($config);
+
+ $timer->setMarker('Marker 1');
// add a new root element in the tree
- $parentId = $tree->add(array('name' => 'myElement'));
+ #$parentId = $tree->add(array('name' => 'myElement'));
// add an element under the new element we added
- $id = $tree->add(array('name' => 'subElement') , $parentId );
+ #$id = $tree->add(array('name' => 'subElement'), $parentId);
// add another element under the parent element we added
- $id = $tree->add(array('name' => 'anotherSubElement') , $parentId );
+ #$id = $tree->add(array('name' => 'anotherSubElement'), $parentId);
+ #$id = $tree->add(array('name' => 'anotherSubElement'), $id);
+$id = 0;
// call 'setup', to build the inner array, so we can work on the structure using the
// given methods
$tree->setup();
+ $timer->setMarker('Marker 2');
+echo '<pre>'; print_r($tree->children); echo '</pre>';
+
+$foo = $tree->getPath(14);
+echo '<pre>'; print_r($foo); echo '</pre>';
+
+$count = count($foo) - 1;
+foreach ($foo as $k => $row) {
+ echo '<a href="?go=forum&amp;id=' . $row['id'] . '">' . $row['name'] . '</a>';
+ if ($k < $count) {
+ echo ' > ';
+ }
+}
+echo '<br />';
+
dumpAllNicely('dump all after creation');
// get the path of the last inserted element
@@ -114,45 +99,41 @@
print "tree->getIdByPath('myElement/subElement')=".$id = $tree->getIdByPath('myElement/subElement');
dumpHelper('$tree->getParent('.$id.')' , 'dump the parent of "myElement/subElement"' , true);
- // you can also use: $tree->data[$id]['parent']
+ // you can also use: $tree->data[$id]['parent_id']
$id = $tree->getIdByPath('myElement');
- dumpHelper('$tree->getChild('.$id.')' , 'dump the child of "myElement"' , true);
- // you can also use: $tree->data[$id]['child']
+ dumpHelper('$tree->getChildren('.$id.', true)' , 'dump the child of "myElement"', true);
$id = $tree->getIdByPath('myElement');
dumpHelper('$tree->getChildren('.$id.')' , 'dump the children of "myElement"');
- // you can also use: $tree->data[$id]['children']
$id = $tree->getIdByPath('myElement/subElement');
- dumpHelper('$tree->getNext('.$id.')' , 'dump the "next" of "myElement/subElement"' , true);
- // you can also use: $tree->data[$id]['next']
+ dumpHelper('$tree->nextSibling('.$id.')' , 'dump the "next" of "myElement/subElement"' , true);
+ // you can also use: $tree->data[$id]['nextId']
$id = $tree->getIdByPath('myElement/anotherSubElement');
- dumpHelper('$tree->getPrevious('.$id.')' , 'dump the "previous" of "myElement/anotherSubElement"' , true);
- // you can also use: $tree->data[$id]['previous']
+ dumpHelper('$tree->prevSibling('.$id.')' , 'dump the "previous" of "myElement/anotherSubElement"' , true);
+ // you can also use: $tree->data[$id]['previousId']
- $id = $tree->getIdByPath('myElement');
- $element = $tree->data[$id]['child']['next']['parent']; // refer to yourself again, in a very complicated way :-)
- dumpHelper('$element[\'id\']' , 'demo of using the internal array, for referencing tree-nodes, see the code');
-
- $id = $tree->getIdByPath('myElement');
- $element = $tree->data[$id]['child']['next']; // refer to the second child of 'myElement'
- dumpHelper('$element[\'id\']' , 'demo2 of using the internal array, for referencing tree-nodes, see the code');
-
$id = $tree->getIdByPath('myElement/anotherSubElement');
- $tree->move($id , 0);
- $tree->setup(); // rebuild the structure again, since we had changed it
+ #$tree->move($id , 0);
+ #$tree->setup(); // rebuild the structure again, since we had changed it
dumpAllNicely( 'dump all, after "myElement/anotherSubElement" was moved under the root' );
- $moveId = $tree->getIdByPath('myElement');
+ #$moveId = $tree->getIdByPath('myElement');
$id = $tree->getIdByPath('anotherSubElement');
- $tree->move( $moveId , $id );
- $tree->setup(); // rebuild the structure again, since we had changed it
- dumpAllNicely('dump all, after "myElement" was moved under the "anotherSubElement"');
+ #$tree->move($moveId , $id);
+ #$tree->setup(); // rebuild the structure again, since we had changed it
+ #dumpAllNicely('dump all, after "myElement" was moved under the "anotherSubElement"');
- $tree->setRemoveRecursively(true);
- $tree->remove(0);
- echo '<font color="red">ALL ELEMENTS HAVE BEEN REMOVED (uncomment this part to keep them in the DB after running this test script)</font>';
+ //$tree->setRemoveRecursively(true);
+ //$tree->remove(0);
+ //echo '<font color="red">ALL ELEMENTS HAVE BEEN REMOVED (uncomment this part to keep them in the DB after running this test script)</font>';
+$timer->stop();
+$timer->display();
+
+$foo = $tree->getRoot();var_dump($foo);
+#$blah = $tree->getChildren($foo); var_dump($blah);
+$aha = $tree->getBranch(); var_dump($aha);
?>
Property changes on: docs/Memory_MDBsimple.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.1
+1.2
Index: docs/TreeView/index.php
===================================================================
--- docs/TreeView/index.php (.../branches/Tree_0_3_0) (revision 321102)
+++ docs/TreeView/index.php (.../trunk) (revision 321102)
@@ -1,22 +1,20 @@
<?php
- //
- // $Id$
- //
-ini_set('include_path',realpath(dirname(__FILE__).'/../../../').':'.realpath(dirname(__FILE__).'/../../../../includes').':'.ini_get('include_path'));
-ini_set('error_reporting',E_ALL);
+// $Id$
+ini_set('error_reporting', E_ALL);
+
##################################################
#
# init template engine
#
// you need the template class from http://sf.net/projects/simpltpl
- if (!@include('HTML/Template/Xipe.php')) {
+ if (!@include 'HTML/Template/Xipe.php') {
print 'sorry, you need the template class PEAR::HTML_Template_Xipe<br>'.
'or if i have time i put the examples <a href="http://os.visionp.de/">here online</a>';
die();
}
- require_once('HTML/Template/Xipe/Filter/TagLib.php');
- $options = array( 'templateDir' => dirname(__FILE__) );
+ require_once 'HTML/Template/Xipe/Filter/TagLib.php';
+ $options = array('templateDir' => dirname(__FILE__));
$tpl = new HTML_Template_Xipe($options);
@@ -24,56 +22,53 @@
#
# actual tree stuff, using Dynamic_DBnested
#
- require_once('Tree/Tree.php');
- $tree = Tree::setup( 'Dynamic_DBnested' , 'mysql://root@localhost/test' , array('table'=>'Tree_Nested') );
+ require_once 'Tree/Tree.php';
+ $tree = Tree::setup('Dynamic_DBnested' , 'mysql://root@localhost/tree_test' , array('table' => 'Tree_Nested'));
- if( @$_REQUEST['action_add'] )
- {
+ if (@$_REQUEST['action_add']) {
$methodCall = "tree->add( {$_REQUEST['newData']} , {$_REQUEST['parentId']} , {$_REQUEST['prevId']} )";
$result = $tree->add( $_REQUEST['newData'] , $_REQUEST['parentId'] , $_REQUEST['prevId'] );
}
- if( @$_REQUEST['action_remove'] )
- {
+ if (@$_REQUEST['action_remove']) {
$methodCall = "$tree->remove( {$_REQUEST['removeId']} )";
$result = $tree->remove( $_REQUEST['removeId'] );
}
- if( @$_REQUEST['action_update'] )
- {
+ if (@$_REQUEST['action_update']) {
$methodCall = "tree->update( {$_REQUEST['updateId']} , {$_REQUEST['updateData']} )";
$result = $tree->update( $_REQUEST['updateId'] , $_REQUEST['updateData'] );
}
- if( @$_REQUEST['action_move'] )
- {
+ if (@$_REQUEST['action_move']) {
$methodCall = "tree->move( {$_REQUEST['move_id']} , {$_REQUEST['move_newParentId']} , {$_REQUEST['move_newPrevId']} )";
$result = $tree->move( $_REQUEST['move_id'] , $_REQUEST['move_newParentId'] , $_REQUEST['move_newPrevId'] );
}
$methodFailed = false;
- if( @PEAR::isError($result) )
+ if (@PEAR::isError($result)) {
$methodFailed = true;
+ }
$fid = @$_REQUEST['fid'];
- if( !$fid )
+ if (!$fid) {
$fid = $tree->getRootId();
+ }
+ $path = $tree->getPath($fid);
+ $children = $tree->getChildren($fid);
- $path = $tree->getPath( $fid );
- $children = $tree->getChildren( $fid );
-
##################################################
#
# actual tree stuff to show the entire tree using Memory_DBnested
#
- require_once('Tree/Tree.php');
- $memTree = Tree::setup( 'Memory_DBnested' , 'mysql://root@localhost/test' ,
- array('table'=>'Tree_Nested') );
+ require_once 'Tree/Tree.php';
+ $memTree = Tree::setup('Memory_DBnested' , 'mysql://root@localhost/test' ,
+ array('table'=>'Tree_Nested'));
$memTree->setup();
$entireTree = $memTree->getNode();
$treeDepth = $memTree->getDepth();
$tpl->compile('index.tpl');
- include($tpl->compiledTemplate);
+ include $tpl->compiledTemplate;
?>
Property changes on: docs/TreeView/index.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.3
+1.4
Index: docs/Dynamic_MDBnested.php
===================================================================
--- docs/Dynamic_MDBnested.php (.../branches/Tree_0_3_0) (revision 321102)
+++ docs/Dynamic_MDBnested.php (.../trunk) (revision 321102)
@@ -1,51 +1,61 @@
<?php
- //
- // $Id$
- //
+// $Id$
-//ini_set('include_path',realpath(dirname(__FILE__).'/../../').':'.realpath(dirname(__FILE__).'/../../../includes').':'.ini_get('include_path'));
-//ini_set('error_reporting',E_ALL);
+// use nested_tree.sql to build the db table
- require_once 'Tree/Tree.php';
+ini_set('error_reporting', E_ALL);
-# $tree = Tree::setupDynamic('MDBnested' , 'mysql://root@localhost/tree_test' , array('table' => 'nestedTree'));
-# OR
- $tree = Tree::setup('Dynamic_MDBnested' , 'mysql://root@localhost/tree_test' , array('table' => 'nestedTree'));
+require_once 'Tree/Tree.php';
- $show[] = '$tree->getRoot()';
- $show[] = '$tree->getElement( 1 )';
- $show[] = '$tree->getChild( 1 )';
- $show[] = '$tree->getPath( 7 )';
- $show[] = '$tree->getPath( 2 )';
- $show[] = '$tree->add( array("name"=>"c0") , 5 )';
- $show[] = '$tree->remove( $res )'; // remove the last element that was added in the line before :-)
- $show[] = '$tree->getRight( 5 )';
- $show[] = '$tree->getLeft( 5 )';
- $show[] = '$tree->getChildren( 1 )';
- $show[] = '$tree->getParent( 2 )';
- $show[] = '$tree->getNext( 2 )';
- $show[] = '$tree->getNext( 4 )';
- $show[] = '$tree->getNext( 8 )';
- $show[] = '$tree->getPrevious( 2 )';
- $show[] = '$tree->getPrevious( 4 )';
- $show[] = '$tree->getPrevious( 8 )';
- $show[] = '$tree->getPreviousId( 8 )';
+$config = array(
+ 'type' => 'Nested',
+ 'storage' => array(
+ 'name' => 'MDB',
+ 'dsn' => 'mysql://root:hamstur@localhost/tree_test',
+ // 'connection' =>
+ ),
+ 'options' => array(
+ 'table' => 'nestedTree',
+ 'order' => 'id',
+ 'fields' => array(),
+ ),
+);
- $show[] = '$tree->move( 4,3 )';
+$tree =& Tree::factoryDynamic($config);
+$show[] = '$tree->getRoot()';
+$show[] = '$tree->getElement( 1 )';
+$show[] = '$tree->getChildren(1, true)';
+$show[] = '$tree->getPath( 7 )';
+$show[] = '$tree->getPath( 2 )';
+// $show[] = '$tree->add( array("name"=>"c0") , 5 )';
+// $show[] = '$tree->remove( $res )'; // remove the last element that was added in the line before :-)
+$show[] = '$tree->getRight( 5 )';
+$show[] = '$tree->getLeft( 5 )';
+$show[] = '$tree->getChildren( 1 )';
+$show[] = '$tree->getParent( 2 )';
+$show[] = '$tree->nextSibling( 2 )';
+$show[] = '$tree->nextSibling( 4 )';
+$show[] = '$tree->nextSibling( 8 )';
+$show[] = '$tree->previousSibling( 2 )';
+$show[] = '$tree->previousSibling( 4 )';
+$show[] = '$tree->previousSibling( 8 )';
- foreach($show as $aRes) {
- echo "<b>$aRes</b><br>";
- eval("\$res=".$aRes.';');
- if ($res == false) {
- print "false";
- } else {
- print_r($res);
- }
- echo '<br><br>';
- }
+$show[] = '$tree->move( 4,3 )';
+foreach ($show as $aRes) {
+ echo "<strong>$aRes</strong><br />";
+ eval("\$res=".$aRes.';');
+ if ($res == false) {
+ print "false";
+ } else {
+ echo '<pre>';
+ print_r($res);
+ echo '</pre>';
+ }
+ echo '<br /><br />';
+}
?>
<a href="http://research.calacademy.org/taf/proceedings/ballew/sld029.htm">the tree structure visualisation</a>
Property changes on: docs/Dynamic_MDBnested.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.1
+1.2
Index: docs/nested_tree.sql
===================================================================
--- docs/nested_tree.sql (.../branches/Tree_0_3_0) (revision 0)
+++ docs/nested_tree.sql (.../trunk) (revision 321102)
@@ -0,0 +1,44 @@
+#
+# Table structure for table `nestedTree`
+#
+
+CREATE TABLE nestedTree (
+ id int(11) NOT NULL default '0',
+ name varchar(255) NOT NULL default '',
+ l int(11) NOT NULL default '0',
+ r int(11) NOT NULL default '0',
+ parent int(11) NOT NULL default '0',
+ comment varchar(255) NOT NULL default '',
+ PRIMARY KEY (id)
+) TYPE=MyISAM;
+
+#
+# Dumping data for table `nestedTree`
+#
+
+INSERT INTO nestedTree VALUES (1, 'Root', 1, 24, 0, '');
+INSERT INTO nestedTree VALUES (2, 'A1', 2, 11, 1, '');
+INSERT INTO nestedTree VALUES (3, 'A2', 12, 23, 1, '');
+INSERT INTO nestedTree VALUES (4, 'A3', 13, 16, 3, '');
+INSERT INTO nestedTree VALUES (5, 'B1', 3, 10, 2, '');
+INSERT INTO nestedTree VALUES (6, 'B2', 17, 18, 3, '');
+INSERT INTO nestedTree VALUES (7, 'B3', 19, 22, 3, '');
+INSERT INTO nestedTree VALUES (8, 'C1', 20, 21, 7, '');
+INSERT INTO nestedTree VALUES (9, 'B4', 14, 15, 4, '');
+# --------------------------------------------------------
+
+#
+# Table structure for table `nestedTree_seq`
+#
+
+CREATE TABLE nestedTree_seq (
+ id int(10) unsigned NOT NULL auto_increment,
+ PRIMARY KEY (id)
+) TYPE=MyISAM;
+
+#
+# Dumping data for table `nestedTree_seq`
+#
+
+INSERT INTO nestedTree_seq VALUES (3);
+
Property changes on: docs/nested_tree.sql
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
Added: svn:keywords
## -0,0 +1 ##
+Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.1
Index: docs/speed_test/setup.php
===================================================================
--- docs/speed_test/setup.php (.../branches/Tree_0_3_0) (revision 0)
+++ docs/speed_test/setup.php (.../trunk) (revision 321102)
@@ -0,0 +1,44 @@
+<?php
+require_once 'Tree/Tree.php';
+
+$config = array(
+ 'type' => 'Nested',
+ 'storage' => array(
+ 'name' => 'MDB2',
+ 'dsn' => 'mysql://root:hamstur@localhost/tree_test',
+ // 'connection' =>
+ ),
+ 'options' => array(
+ 'table' => 'nestedTree1',
+ 'order' => 'id',
+ 'fields' => array(),
+ ),
+);
+
+$tree =& Tree::factoryDynamic($config);
+
+
+$tree->add(array('name' => 'c0') , 0);
+$tree->add(array('name' => 'c1') , 1);
+$tree->add(array('name' => 'c2') , 2);
+$tree->add(array('name' => 'c3') , 3);
+
+$tree->add(array('name' => 'c0') , 4);
+$tree->add(array('name' => 'c1') , 5);
+$tree->add(array('name' => 'c2') , 6);
+$tree->add(array('name' => 'c3') , 7);
+
+$tree->add(array('name' => 'c0') , 8);
+$tree->add(array('name' => 'c1') , 9);
+$tree->add(array('name' => 'c2') , 10);
+$tree->add(array('name' => 'c3') , 11);
+
+$tree->add(array('name' => 'c0') , 12);
+$tree->add(array('name' => 'c1') , 13);
+$tree->add(array('name' => 'c2') , 14);
+$tree->add(array('name' => 'c3') , 15);
+
+$tree->add(array('name' => 'c0') , 16);
+$tree->add(array('name' => 'c1') , 17);
+$tree->add(array('name' => 'c2') , 18);
+$tree->add(array('name' => 'c3') , 19);
\ No newline at end of file
Property changes on: docs/speed_test/setup.php
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.1
Added: svn:eol-style
## -0,0 +1 ##
+native
Index: docs/speed_test/speed.php
===================================================================
--- docs/speed_test/speed.php (.../branches/Tree_0_3_0) (revision 0)
+++ docs/speed_test/speed.php (.../trunk) (revision 321102)
@@ -0,0 +1,35 @@
+<?php
+require_once 'Tree/Tree.php';
+
+$config = array(
+ 'type' => 'Nested',
+ 'storage' => array(
+ 'name' => 'MDB2',
+ 'dsn' => 'mysql://root:hamstur@localhost/tree_test',
+ // 'connection' =>
+ ),
+ 'options' => array(
+ 'table' => 'nestedTree1',
+ 'order' => 'id',
+ 'fields' => array(),
+ ),
+);
+
+$tree =& Tree::factoryMemory($config);
+$tree->setup();
+
+$root = $tree->getRoot();
+
+echo str_repeat('-', $tree->getLevel($root['id'])) . $root['id'] . ' (parent: ' . $root['parent_id'] . ')<br />';
+recursive($root['id']);
+
+// Usually it's a good idea to do -1 on each level since there can only be one root node
+function recursive($id)
+{
+ global $tree;
+ $blah = $tree->getChildren($id);
+ foreach ($blah as $row) {
+ echo str_repeat('-', $tree->getLevel($row['id'])) . $row['id'] . ' (parent: ' . $row['parent_id'] . ')<br />';
+ recursive($row['id']);
+ }
+}
\ No newline at end of file
Property changes on: docs/speed_test/speed.php
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.1
Added: svn:eol-style
## -0,0 +1 ##
+native
Index: docs/funcs.php
===================================================================
--- docs/funcs.php (.../branches/Tree_0_3_0) (revision 0)
+++ docs/funcs.php (.../trunk) (revision 321102)
@@ -0,0 +1,48 @@
+<?php
+// $Id$
+
+ini_set('error_reporting', E_ALL);
+
+/**
+* this is a helper function, so i dont have to write so many prints :-)
+* @param array $para the result returned by some method, that will be dumped
+* @param string $string the explaining string
+*/
+function dumpHelper($para, $string = '', $addArray = false)
+{
+ global $tree, $element;
+
+ if ($addArray) {
+ eval("\$res=array(".$para.');');
+ } else {
+ eval("\$res=".$para.';');
+ }
+ echo '<strong>' . $para . ' </strong><i><u><span style="color: #008000;">' . $string . '</span></u></i><br>';
+ // this method dumps to the screen, since print_r or var_dump dont
+ // work too good here, because the inner array is recursive
+ // well, it looks ugly but one can see what is meant :-)
+ $tree->varDump($res);
+ echo '<br />';
+
+}
+
+/**
+* dumps the entire structure nicely
+* @param string $string the explaining string
+*/
+function dumpAllNicely($string = '')
+{
+ global $tree;
+
+ echo '<i><span style="color: #008000; text-decoration: underline;">' . $string . '</span></i><br>';
+ $all = $tree->getBranch(); // get the entire structure sorted as the tree is, so we can simply foreach through it and show it
+ foreach ($all as $aElement) {
+ for ($i = 0; $i < $aElement['level']; ++$i) {
+ echo '&nbsp; &nbsp; ';
+ }
+ echo '<span style="color: red">' . $aElement['name'] . '</span> ===&gt; ';
+ $tree->varDump(array($aElement));
+ }
+ echo '<br />';
+
+}
\ No newline at end of file
Property changes on: docs/funcs.php
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
Added: svn:keywords
## -0,0 +1 ##
+Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.1
Index: docs/Memory_DBnested.php
===================================================================
--- docs/Memory_DBnested.php (.../branches/Tree_0_3_0) (revision 321102)
+++ docs/Memory_DBnested.php (.../trunk) (revision 321102)
@@ -1,58 +1,14 @@
<?php
// $Id$
-ini_set('error_reporting',E_ALL);
+include_once 'funcs.php';
- /**
- * this is a helper function, so i dont have to write so many prints :-)
- * @param array $para the result returned by some method, that will be dumped
- * @param string $string the explaining string
- */
- function dumpHelper($para, $string = '', $addArray = false)
- {
- global $tree, $element;
- if ($addArray) {
- eval( "\$res=array(".$para.');' );
- } else {
- eval( "\$res=".$para.';' );
- }
- echo '<b>'.$para.' </b><i><u><font color="#008000">'.$string.'</font></u></i><br />';
- // this method dumps to the screen, since print_r or var_dump dont
- // work too good here, because the inner array is recursive
- // well, it looks ugly but one can see what is meant :-)
- $tree->varDump($res);
- echo '<br />';
-
- }
-
- /**
- * dumps the entire structure nicely
- * @param string $string the explaining string
- */
- function dumpAllNicely($string = '')
- {
- global $tree;
-
- echo '<i><u><font color="#008000">'.$string.'</font></u></i><br />';
- $all = $tree->getNode(); // get the entire structure sorted as the tree is, so we can simply foreach through it and show it
- foreach($all as $aElement) {
- for ($i = 0; $i < $aElement['level']; $i++) {
- echo '&nbsp; &nbsp; ';
- }
- echo '<font color="red">'.$aElement['name'].'</font> ===&gt; ';
- $tree->varDump(array($aElement));
- }
- echo '<br />';
-
- }
-
-
/*
use this to build the db table
- CREATE TABLE Memory_Nested_DB (
+ CREATE TABLE Memory_nestedTree (
id int(11) NOT NULL default '0',
name varchar(255) NOT NULL default '',
l int(11) NOT NULL default '0',
@@ -62,7 +18,6 @@
PRIMARY KEY (id)
);
-
This example demonstrates how to manage trees
that are saved in a DB, it uses a very simple
DB-structure, not nested trees (ok, that sucks, but it can be implemented :-) )
@@ -78,10 +33,6 @@
require_once 'Tree/Tree.php';
// define the DB-table where the data shall be read from
- $options = array('table' => 'Memory_Nested_DB'
- ,'whereAddOn' => "comment=''"
- );
-
// calling 'setupMemory' means to retreive a class, which works on trees,
// that are temporarily stored in the memory, in an array
// this means the entire tree is available at all time !!!
@@ -91,20 +42,34 @@
// the class Memory/DBnested is only kind of a wrapper to read the entire tree
// and let u work on it, which to use should be chosen on case by case basis
+$config = array(
+ 'type' => 'Nested',
+ 'storage' => array(
+ 'name' => 'DB',
+ 'dsn' => 'mysql://root:hamstur@localhost/tree_test',
+ // 'connection' =>
+ ),
+ 'options' => array(
+ 'table' => 'nestedTree',
+ 'order' => 'id',
+ 'fields' => array(),
+ 'whereAddOn' => "comment=''"
+ ),
+);
+
+
// using 'setupMemory'
- $tree = Tree::setupMemory('DBnested',
- 'mysql://root@localhost/tree_test', // the DSN
- $options); // pass the options we had assigned up there
+ $tree =& Tree::factoryMemory($config);
// add a new root element in the tree
- $rootId = $tree->add(array('name' => 'myElement'));
+ #$rootId = $tree->add(array('name' => 'myElement'));
// add an element under the new element we added
- $id = $tree->add(array('name' => 'subElement') , $rootId);
+ #$id = $tree->add(array('name' => 'subElement') , $rootId);
// add another element under the parent element we added
- $id = $tree->add(array('name' => 'anotherSubElement') , $rootId , $id);
-
+ #$id = $tree->add(array('name' => 'anotherSubElement') , $rootId , $id);
+$id = 0;
// call 'setup', to build the inner array, so we can work on the structure using the
// given methods
$tree->setup();
@@ -119,7 +84,7 @@
// you can also use: $tree->data[$id]['parent']
$id = $tree->getIdByPath('myElement');
- dumpHelper('$tree->getChild('.$id.')' , 'dump the child of "myElement"' , true);
+ dumpHelper('$tree->getChildren('.$id.', true)' , 'dump the child of "myElement"' , true);
// you can also use: $tree->data[$id]['child']
$id = $tree->getIdByPath('myElement');
@@ -127,11 +92,11 @@
// you can also use: $tree->data[$id]['children']
$id = $tree->getIdByPath('myElement/subElement');
- dumpHelper('$tree->getNext('.$id.')' , 'dump the "next" of "myElement/subElement"' , true);
+ dumpHelper('$tree->nextSibling('.$id.')' , 'dump the "next" of "myElement/subElement"' , true);
// you can also use: $tree->data[$id]['next']
$id = $tree->getIdByPath('myElement/anotherSubElement');
- dumpHelper('$tree->getPrevious('.$id.')' , 'dump the "previous" of "myElement/anotherSubElement"' , true);
+ dumpHelper('$tree->previousSibling('.$id.')' , 'dump the "previous" of "myElement/anotherSubElement"' , true);
// you can also use: $tree->data[$id]['previous']
$id = $tree->getIdByPath('myElement');
@@ -141,18 +106,18 @@
$id = $tree->getIdByPath('myElement');
$element = $tree->data[$id]['child']['next']; // refer to the second child of 'myElement'
dumpHelper('$element[\'id\']' , 'demo2 of using the internal array, for referencing tree-nodes, see the code');
-/*
+
$id = $tree->getIdByPath('myElement/anotherSubElement');
- $tree->move( $id , 0 );
+ $tree->move($id , 0);
$tree->setup(); // rebuild the structure again, since we had changed it
dumpAllNicely( 'dump all, after "myElement/anotherSubElement" was moved under the root' );
$moveId = $tree->getIdByPath('myElement');
$id = $tree->getIdByPath('anotherSubElement');
- $tree->move( $moveId , $id );
+ $tree->move($moveId , $id);
$tree->setup(); // rebuild the structure again, since we had changed it
dumpAllNicely( 'dump all, after "myElement" was moved under the "anotherSubElement"' );
-*/
+
$tree->setRemoveRecursively(true);
$tree->remove($rootId);
echo '<font color="red">ALL ELEMENTS HAVE BEEN REMOVED (uncomment this part to keep them in the DB after running this test script)</font>';
Property changes on: docs/Memory_DBnested.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.3
+1.4
Index: docs/TreeEditor/index.tpl
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/vnd.groove-tool-template
Index: docs/TreeEditor/index.tpl
===================================================================
--- docs/TreeEditor/index.tpl (.../branches/Tree_0_3_0) (revision 321102)
+++ docs/TreeEditor/index.tpl (.../trunk) (revision 321102)
Property changes on: docs/TreeEditor/index.tpl
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.1
+1.2
Index: docs/TreeEditor/treeClass.php
===================================================================
--- docs/TreeEditor/treeClass.php (.../branches/Tree_0_3_0) (revision 321102)
+++ docs/TreeEditor/treeClass.php (.../trunk) (revision 321102)
@@ -1,18 +1,22 @@
<?php
//
// $Log$
+// Revision 1.1 2003/01/30 17:18:24 cain
+// - moved all examples to docs
+// - and make them work properly
+//
// Revision 1.1 2002/08/23 17:18:28 cain
// - a good example to show how the tree works
//
//
-require_once('Tree/Memory.php');
+require_once 'Tree/Memory.php';
class treeClass extends Tree_Memory
{
- function getPathAsString( $id )
+ function getPathAsString($id)
{
return preg_replace('/Root\s-\s/','',parent::getPathAsString( $id , ' - ' ));
}
@@ -34,25 +38,22 @@
* @return mixed an array if the node shall be visible
* nothing if the node shall not be shown
*/
- function _walkForGettingVisibleFolders( $node )
+ function _walkForGettingVisibleFolders($node)
{
global $session;
- if( $node['id']==$this->getRootId() )
+ if ($node['id'] == $this->getRootId()) {
return $node;
-
+ }
$parentsIds = $this->getParentsIds($node['id']);
- if( !@$this->_unfoldAll )
- {
- foreach( $parentsIds as $aParentId )
- {
- if( !@$session->temp->openProjectFolders[$aParentId] &&
- $aParentId!=$node['id']) // dont check the node itself, since we only look if the parents are openend, then this $node is shown!
+ if (!@$this->_unfoldAll) {
+ foreach ($parentsIds as $aParentId) {
+ if (!@$session->temp->openProjectFolders[$aParentId] &&
+ $aParentId != $node['id']) { // dont check the node itself, since we only look if the parents are openend, then this $node is shown!
return false;
+ }
}
- }
- else
- {
+ } else {
// if all folders shall be unfolded save the unfold-ids in the session
$session->temp->openProjectFolders[$node['id']] = $node['id'];
}
@@ -71,32 +72,24 @@
function getAllVisible()
{
$this->unfoldHandler();
- return $this->walk( array(&$this,'_walkForGettingVisibleFolders') , 0 , 'ifArray' );
+ return $this->walk(array(&$this, '_walkForGettingVisibleFolders'), 0, 'ifArray');
}
function unfoldHandler()
{
global $session;
- if( @$_REQUEST['unfoldAll'] )
- {
+ if (@$_REQUEST['unfoldAll']) {
$this->_unfoldAll = true;
}
- if( @$_REQUEST['unfold'] )
- {
- if( @$session->temp->openProjectFolders[$_REQUEST['unfold']] )
- {
+ if (@$_REQUEST['unfold']) {
+ if (@$session->temp->openProjectFolders[$_REQUEST['unfold']]) {
unset($session->temp->openProjectFolders[$_REQUEST['unfold']]);
- }
- else
- {
+ } else {
$session->temp->openProjectFolders[$_REQUEST['unfold']] = $_REQUEST['unfold'];
}
}
}
-
-
}
-
?>
Property changes on: docs/TreeEditor/treeClass.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.1
+1.2
Index: docs/TreeEditor/index.php
===================================================================
--- docs/TreeEditor/index.php (.../branches/Tree_0_3_0) (revision 321102)
+++ docs/TreeEditor/index.php (.../trunk) (revision 321102)
@@ -1,105 +1,109 @@
<?php
- //
- // $Id$
- //
-//ini_set('include_path',realpath(dirname(__FILE__).'/../../../').':'.realpath(dirname(__FILE__).'/../../../../includes').':'.ini_get('include_path'));
-//ini_set('error_reporting',E_ALL);
+// $Id$
+ini_set('error_reporting', E_ALL);
+
##################################################
#
# init template engine
#
- // you need the template class from http://sf.net/projects/simpltpl
- if (!@include('HTML/Template/Xipe.php')) {
+ if (!@include 'HTML/Template/Xipe.php') {
print 'sorry, you need the template class PEAR::HTML_Template_Xipe<br>'.
'or if i have time i put the examples <a href="http://os.visionp.de/">here online</a>';
die();
}
- require_once('HTML/Template/Xipe/Filter/TagLib.php');
- $options = array( 'templateDir' => dirname(__FILE__) );
+ require_once 'HTML/Template/Xipe/Filter/TagLib.php';
+ $options = array('templateDir' => dirname(__FILE__));
$tpl = new HTML_Template_Xipe($options);
- require_once('HTML/Template/Xipe/Filter/Modifier.php');
+ require_once 'HTML/Template/Xipe/Filter/Modifier.php';
$modifiers = new HTML_Template_Xipe_Filter_Modifier($tpl->options);
- $tpl->registerPrefilter(array(&$modifiers,'imgSrc'),
- array(dirname(__FILE__),'http://'.$_SERVER['HTTP_HOST'].dirname($_SERVER['PHP_SELF'])));
+ $tpl->registerPrefilter(array(&$modifiers, 'imgSrc'),
+ array(dirname(__FILE__), 'http://'.$_SERVER['HTTP_HOST'].dirname($_SERVER['PHP_SELF'])));
// session stuff to save the opened folders etc.
session_start();
- if(!session_is_registered('session'))
- {
+ if (empty($_SESSION['session'])) {
$session = new stdClass; // standard PHP-class constructor
- session_register('session');
- $session->data = array();
+ $_SESSION['session'] = $session;
$session->use = 'Filesystem';
+ } else {
+ // since the class is read from the session it is not automatically made global
+ $session = $_SESSION['session'];
}
- else // since the class is read from the session it is not automatically made global
- {
- $session = &$_SESSION['session'];
- }
+ $session->data = array();
+
// set the source to use
- if( @$_REQUEST['use_DB'] )
+ if (@$_REQUEST['use_DB']) {
$session->use = 'DB';
- if( @$_REQUEST['use_Filesystem'] )
+ }
+ if (@$_REQUEST['use_MDB']) {
+ $session->use = 'MDB';
+ }
+ if (@$_REQUEST['use_Filesystem']) {
$session->use = 'Filesystem';
- if( @$_REQUEST['use_XML'] )
+ }
+ if (@$_REQUEST['use_XML']) {
$session->use = 'XML';
- if( @$_REQUEST['use_Array'] )
+ }
+ if (@$_REQUEST['use_Array']) {
$session->use = 'Array';
+ }
+ if (!isset($session->use)) {
+ $session->use = 'DB';
+ }
+
##################################################
#
# actual tree stuff
#
- define('TABLE_TREE','Tree_Nested');
- define('DB_DSN','mysql://root@localhost/test');
+ define('TABLE_TREE', 'Tree_Nested');
+ define('DB_DSN', 'mysql://root@localhost/tree_test');
- require_once('treeClass.php');
- if( $session->use == 'DB' )
- {
- $options = array( 'table' => TABLE_TREE , 'order' => 'name');
- $tree = new treeClass( 'DBnested' , DB_DSN , $options );
- }
- if( $session->use == 'Filesystem' )
- {
- # to let it work on the filesystem :-)
- $options = array( 'order' => 'name');
- $tree = new treeClass( 'Filesystem' , dirname(__FILE__).'/tmp' , $options );
- }
- if( $session->use == 'XML' )
- {
- $tree = new treeClass( 'XML' , dirname(__FILE__).'/config.xml' );
- }
- if( $session->use == 'Array' )
- {
- // the actual data for the tree, they have to have the given structure
- $arrayData = array( 'name'=>'Root',
- 'children'=>array(
- array('name'=>'dir1'),
- array('name'=>'dir2',
- 'children'=>array(
- array('name'=>'dir2_1'),
- array('name'=>'dir2_2'),
- )
- ),
- array('name'=>'dir3')
- )
- );
+ require_once 'treeClass.php';
+ switch ($session->use) {
+ case 'MDB':
+ $options = array('table' => TABLE_TREE , 'order' => 'name');
+ $tree = new treeClass('MDBnested', DB_DSN, $options);
+ break;
+ case 'Filesystem':
+ # to let it work on the filesystem :-)
+ $options = array('order' => 'name');
+ $tree = new treeClass('Filesystem', '/tmp', $options);
+ case 'XML':
+ $tree = new treeClass('XML', dirname(__FILE__).'/config.xml');
+ break;
+ case 'Array':
+ // the actual data for the tree, they have to have the given structure
+ $arrayData = array( 'name'=>'Root',
+ 'children'=>array(
+ array('name'=>'dir1'),
+ array('name'=>'dir2',
+ 'children'=>array(
+ array('name'=>'dir2_1'),
+ array('name'=>'dir2_2'),
+ )
+ ),
+ array('name'=>'dir3')
+ )
+ );
- // any on an array
- $options = array( 'order' => 'name');
- $tree = new treeClass( 'Array' , $arrayData , $options );
+ // any on an array
+ $options = array('order' => 'name');
+ $tree = new treeClass('Array', $arrayData, $options);
+ break;
+ case 'DB':
+ default:
+ $options = array('table' => TABLE_TREE , 'order' => 'name');
+ $tree = new treeClass('DBnested', DB_DSN, $options);
+ break;
}
-
-
-
-
- if( PEAR::isError($res=$tree->setup()) )
- {
+ if (PEAR::isError($res = $tree->setup())) {
$methodFailed = true;
$results[] = $res;
}
@@ -108,36 +112,33 @@
// detect action
- if( @$_REQUEST['action_copy'] || @$_REQUEST['action_copy_x'] ||
- @$_REQUEST['action_cut'] || @$_REQUEST['action_cut_x'] )
+ if (@$_REQUEST['action_copy'] || @$_REQUEST['action_copy_x'] ||
+ @$_REQUEST['action_cut'] || @$_REQUEST['action_cut_x'])
{
- if( @$_REQUEST['action_copy'] || @$_REQUEST['action_copy_x']) $session->action = 'copy';
- if( @$_REQUEST['action_cut'] || @$_REQUEST['action_cut_x'] ) $session->action = 'cut';
+ if (@$_REQUEST['action_copy'] || @$_REQUEST['action_copy_x']) {
+ $session->action = 'copy';
+ }
+ if (@$_REQUEST['action_cut'] || @$_REQUEST['action_cut_x'] ) {
+ $session->action = 'cut';
+ }
- if( is_array($_REQUEST['selectedNodes']) && sizeof($_REQUEST['selectedNodes']))
- {
+ if (is_array($_REQUEST['selectedNodes']) &&
+ sizeof($_REQUEST['selectedNodes'])
+ ) {
$session->data = $_REQUEST['selectedNodes'];
- }
- else
- {
+ } else {
$session->action = '';
}
}
- if( @$_REQUEST['action_paste'] || @$_REQUEST['action_paste_x'] )
- {
- if( is_array($session->data) && sizeof($session->data))
- {
- if( $session->action == 'copy' )
- {
- if( is_array($_REQUEST['selectedNodes']) && sizeof($_REQUEST['selectedNodes']))
- {
+ if (@$_REQUEST['action_paste'] || @$_REQUEST['action_paste_x']) {
+ if (is_array($session->data) && sizeof($session->data)) {
+ if ($session->action == 'copy') {
+ if (is_array($_REQUEST['selectedNodes']) && sizeof($_REQUEST['selectedNodes'])) {
$dest = $_REQUEST['selectedNodes'];
$sources = $session->data;
- foreach( $sources as $aSrc )
- {
- foreach( $dest as $aDest )
- {
+ foreach($sources as $aSrc) {
+ foreach($dest as $aDest) {
$methodCalls[] = "tree->copy( $aSrc , $aDest )";
$results[] = $tree->copy( $aSrc , $aDest );
}
@@ -147,25 +148,18 @@
$session->data = array();
unset($session->action);
$tree->setup();
- }
- else
- {
+ } else {
$methodFailed = true;
$results = 'Please choose destination folder(s) to paste to!';
}
}
- if( $session->action == 'cut')
- {
- if( !$_REQUEST['moveDest'] )
- {
+ if ($session->action == 'cut') {
+ if (!$_REQUEST['moveDest']) {
$methodFailed = true;
$results = 'Please choose a destination to paste to!';
- }
- else
- {
- foreach( $session->data as $aNodeId )
- {
+ } else {
+ foreach($session->data as $aNodeId) {
$methodCalls[] = "tree->move( $aNodeId , {$_REQUEST['moveDest']} )";
$results[] = $tree->move( $aNodeId , $_REQUEST['moveDest'] );
}
@@ -177,24 +171,21 @@
}
}
- if( (@$_REQUEST['action_delete'] || @$_REQUEST['action_delete_x']) &&
- is_array($_REQUEST['selectedNodes']) && sizeof($_REQUEST['selectedNodes']) )
+ if ((@$_REQUEST['action_delete'] || @$_REQUEST['action_delete_x']) &&
+ is_array($_REQUEST['selectedNodes']) && sizeof($_REQUEST['selectedNodes']))
{
$rootId = $tree->getRootId();
- foreach( $_REQUEST['selectedNodes'] as $aNodeId )
- {
- if( $rootId == $aNodeId )
- {
+ foreach($_REQUEST['selectedNodes'] as $aNodeId) {
+ if ($rootId == $aNodeId) {
$methodCalls[] = 0;
$results[] = 'Cant remove Root with this application!';
$methodFailed = true;
- }
- else
- {
+ } else {
$methodCalls[] = "tree->remove( $aNodeId )";
- $res = $tree->remove( $aNodeId );
- if(PEAR::isError($res))
+ $res = $tree->remove($aNodeId);
+ if (PEAR::isError($res)) {
$methodFailed = true;
+ }
$results[] = $res;
}
}
@@ -204,16 +195,16 @@
}
- if( @$_REQUEST['action_add'] &&
+ if (@$_REQUEST['action_add'] &&
is_array($_REQUEST['selectedNodes']) && sizeof($_REQUEST['selectedNodes']) &&
- $_REQUEST['newFolder'] )
+ $_REQUEST['newFolder'])
{
- foreach( $_REQUEST['selectedNodes'] as $aNodeId )
- {
+ foreach($_REQUEST['selectedNodes'] as $aNodeId) {
$methodCalls[] = "tree->add( {$_REQUEST['newFolder']} , $aNodeId )";
- $res = $tree->add( $_REQUEST['newFolder'] , $aNodeId );
- if(PEAR::isError($res))
+ $res = $tree->add($_REQUEST['newFolder'] , $aNodeId);
+ if (PEAR::isError($res)) {
$methodFailed = true;
+ }
$results[] = $res;
}
$session->data = array();
@@ -224,13 +215,14 @@
$allVisibleFolders = $tree->getAllVisible();
- if( !@is_array($_REQUEST['selectedNodes']) )
+ if (!@is_array($_REQUEST['selectedNodes'])) {
$_REQUEST['selectedNodes'] = array();
+ }
##################################################
#
# show the template
#
$tpl->compile('index.tpl');
- include($tpl->compiledTemplate);
+ include $tpl->compiledTemplate;
?>
Property changes on: docs/TreeEditor/index.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.2
+1.3
Index: docs/umbrello-uml.xmi
===================================================================
--- docs/umbrello-uml.xmi (.../branches/Tree_0_3_0) (revision 321102)
+++ docs/umbrello-uml.xmi (.../trunk) (revision 321102)
@@ -1,150 +1,236 @@
<?xml version="1.0" encoding="UTF-8"?>
-<XMI xmlns:UML="org.omg/standards/UML" verified="false" timestamp="" xmi.version="1.2" >
+<XMI xmlns:UML="http://schema.omg.org/spec/UML/1.3" verified="false" timestamp="2006-04-21T06:27:41" xmi.version="1.2" >
<XMI.header>
<XMI.documentation>
<XMI.exporter>umbrello uml modeller http://uml.sf.net</XMI.exporter>
- <XMI.exporterVersion>1.1</XMI.exporterVersion>
+ <XMI.exporterVersion>1.5.1</XMI.exporterVersion>
+ <XMI.exporterEncoding>UnicodeUTF8</XMI.exporterEncoding>
</XMI.documentation>
- <XMI.model xmi.name="uml" href="/home/wk/public_html/timetool/includes_cvs/Tree/docs/uml.xmi" />
<XMI.metamodel xmi.name="UML" href="UML.xml" xmi.version="1.3" />
</XMI.header>
<XMI.content>
- <docsettings viewid="34" documentation="" uniqueid="48" />
- <umlobjects>
- <UML:Class stereotype="" package="Tree" xmi.id="35" abstract="0" documentation="" name="Tree" static="0" scope="200" >
- <UML:Operation stereotype="" package="" xmi.id="36" type="void" abstract="0" documentation="" name="setup" static="0" scope="200" >
- <UML:Parameter stereotype="" package="" xmi.id="1" value="" type="string" abstract="0" documentation="" name="type" static="0" scope="200" />
- <UML:Parameter stereotype="" package="" xmi.id="2" value="" type="string" abstract="0" documentation="" name="dsn" static="0" scope="200" />
- <UML:Parameter stereotype="" package="" xmi.id="3" value="array()" type="int" abstract="0" documentation="" name="options" static="0" scope="200" />
- </UML:Operation>
- </UML:Class>
- <UML:Class stereotype="" package="Tree" xmi.id="37" abstract="0" documentation="" name="Tree_Common" static="0" scope="200" >
- <UML:Attribute stereotype="" package="" xmi.id="38" value="array()" type="int" abstract="0" documentation="" name="options" static="0" scope="200" />
- </UML:Class>
- <UML:Class stereotype="" package="Tree" xmi.id="40" abstract="0" documentation="" name="Tree_Memory" static="0" scope="200" />
- <UML:Class stereotype="" package="Tree" xmi.id="41" abstract="0" documentation="" name="Tree_Dynamic_DBnested" static="0" scope="200" />
- <UML:Class stereotype="" package="Tree" xmi.id="42" abstract="0" documentation="" name="Tree_Memory_DBnested" static="0" scope="200" />
- <UML:Class stereotype="" package="Tree" xmi.id="43" abstract="0" documentation="" name="Tree_Memory_Array" static="0" scope="200" />
- <UML:Class stereotype="" package="Tree" xmi.id="44" abstract="0" documentation="" name="Tree_Memory_DBsimple" static="0" scope="200" />
- <UML:Class stereotype="" package="Tree" xmi.id="45" abstract="0" documentation="" name="Tree_Memory_Filesystem" static="0" scope="200" />
- <UML:Class stereotype="" package="Tree" xmi.id="46" abstract="0" documentation="" name="Tree_Memory_XML" static="0" scope="200" />
- <UML:Class stereotype="" package="Tree" xmi.id="47" abstract="0" documentation="" name="Tree_Options" static="0" scope="200" />
- <UML:Class stereotype="" package="Tree" xmi.id="48" abstract="0" documentation="" name="Tree_OptionsDB" static="0" scope="200" />
- </umlobjects>
+ <UML:Model isSpecification="false" isLeaf="false" isRoot="false" xmi.id="m1" isAbstract="false" name="UML Model" >
+ <UML:Namespace.ownedElement>
+ <UML:Package isSpecification="false" isLeaf="false" visibility="public" namespace="m1" xmi.id="50" isRoot="false" isAbstract="false" name="Tree" >
+ <UML:Namespace.ownedElement>
+ <UML:Class isSpecification="false" isLeaf="false" visibility="public" namespace="50" xmi.id="35" isRoot="false" isAbstract="false" name="Tree" >
+ <UML:Classifier.feature>
+ <UML:Operation isSpecification="false" isLeaf="false" visibility="public" xmi.id="36" isRoot="false" isAbstract="false" isQuery="false" name="setup" >
+ <UML:BehavioralFeature.parameter>
+ <UML:Parameter kind="return" xmi.id="135" type="97" />
+ <UML:Parameter isSpecification="false" visibility="public" xmi.id="1" value="" type="98" name="type" />
+ <UML:Parameter isSpecification="false" visibility="public" xmi.id="2" value="" type="98" name="dsn" />
+ <UML:Parameter isSpecification="false" visibility="public" xmi.id="3" value="array()" type="99" name="options" />
+ </UML:BehavioralFeature.parameter>
+ </UML:Operation>
+ </UML:Classifier.feature>
+ </UML:Class>
+ <UML:Class isSpecification="false" isLeaf="false" visibility="public" namespace="50" xmi.id="37" isRoot="false" isAbstract="false" name="Tree_Common" >
+ <UML:Classifier.feature>
+ <UML:Attribute isSpecification="false" visibility="public" xmi.id="38" initialValue="array()" type="99" name="options" />
+ </UML:Classifier.feature>
+ </UML:Class>
+ <UML:Class isSpecification="false" isLeaf="false" visibility="public" namespace="50" xmi.id="40" isRoot="false" isAbstract="false" name="Tree_Memory" >
+ <UML:GeneralizableElement.generalization>
+ <UML:Generalization xmi.idref="61" />
+ <UML:Generalization xmi.idref="117" />
+ </UML:GeneralizableElement.generalization>
+ </UML:Class>
+ <UML:Class isSpecification="false" isLeaf="false" visibility="public" namespace="50" xmi.id="41" isRoot="false" isAbstract="false" name="Tree_Dynamic_SQLnested" >
+ <UML:GeneralizableElement.generalization>
+ <UML:Generalization xmi.idref="64" />
+ <UML:Generalization xmi.idref="112" />
+ </UML:GeneralizableElement.generalization>
+ </UML:Class>
+ <UML:Class isSpecification="false" isLeaf="false" visibility="public" namespace="50" xmi.id="42" isRoot="false" isAbstract="false" name="Tree_Memory_SQLnested" >
+ <UML:GeneralizableElement.generalization>
+ <UML:Generalization xmi.idref="67" />
+ </UML:GeneralizableElement.generalization>
+ </UML:Class>
+ <UML:Class isSpecification="false" isLeaf="false" visibility="public" namespace="50" xmi.id="43" isRoot="false" isAbstract="false" name="Tree_Memory_Array" />
+ <UML:Class isSpecification="false" isLeaf="false" visibility="public" namespace="50" xmi.id="44" isRoot="false" isAbstract="false" name="Tree_Memory_SQLsimple" />
+ <UML:Class isSpecification="false" isLeaf="false" visibility="public" namespace="50" xmi.id="45" isRoot="false" isAbstract="false" name="Tree_Memory_Filesystem" />
+ <UML:Class isSpecification="false" isLeaf="false" visibility="public" namespace="50" xmi.id="46" isRoot="false" isAbstract="false" name="Tree_Memory_XML" />
+ <UML:Class isSpecification="false" isLeaf="false" visibility="public" namespace="50" xmi.id="47" isRoot="false" isAbstract="false" name="Tree_Options" >
+ <UML:GeneralizableElement.generalization>
+ <UML:Generalization xmi.idref="79" />
+ </UML:GeneralizableElement.generalization>
+ </UML:Class>
+ <UML:Class isSpecification="false" isLeaf="false" visibility="public" namespace="50" xmi.id="48" isRoot="false" isAbstract="false" name="Tree_OptionsDB" >
+ <UML:GeneralizableElement.generalization>
+ <UML:Generalization xmi.idref="76" />
+ <UML:Generalization xmi.idref="107" />
+ </UML:GeneralizableElement.generalization>
+ </UML:Class>
+ </UML:Namespace.ownedElement>
+ </UML:Package>
+ <UML:Class isSpecification="false" isLeaf="false" visibility="public" namespace="m1" xmi.id="97" isRoot="false" isAbstract="false" name="void" />
+ <UML:Class isSpecification="false" isLeaf="false" visibility="public" namespace="m1" xmi.id="98" isRoot="false" isAbstract="false" name="string" />
+ <UML:Class isSpecification="false" isLeaf="false" visibility="public" namespace="m1" xmi.id="99" isRoot="false" isAbstract="false" name="int" />
+ <UML:Generalization isSpecification="false" child="40" visibility="public" namespace="m1" xmi.id="61" parent="37" discriminator="" name="" />
+ <UML:Generalization isSpecification="false" child="41" visibility="public" namespace="m1" xmi.id="64" parent="37" discriminator="" name="" />
+ <UML:Generalization isSpecification="false" child="42" visibility="public" namespace="m1" xmi.id="67" parent="41" discriminator="" name="" />
+ <UML:Association isSpecification="false" visibility="public" namespace="m1" xmi.id="70" name="" >
+ <UML:Association.connection>
+ <UML:AssociationEnd isSpecification="false" visibility="public" changeability="changeable" isNavigable="false" xmi.id="71" aggregation="none" type="35" name="" />
+ <UML:AssociationEnd isSpecification="false" visibility="public" changeability="changeable" isNavigable="true" xmi.id="72" aggregation="none" type="40" name="" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association isSpecification="false" visibility="public" namespace="m1" xmi.id="73" name="" >
+ <UML:Association.connection>
+ <UML:AssociationEnd isSpecification="false" visibility="public" changeability="changeable" isNavigable="false" xmi.id="74" aggregation="none" type="35" name="" />
+ <UML:AssociationEnd isSpecification="false" visibility="public" changeability="changeable" isNavigable="true" xmi.id="75" aggregation="none" type="41" name="" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Generalization isSpecification="false" child="48" visibility="public" namespace="m1" xmi.id="76" parent="37" discriminator="" name="" />
+ <UML:Generalization isSpecification="false" child="47" visibility="public" namespace="m1" xmi.id="79" parent="48" discriminator="" name="" />
+ <UML:Association isSpecification="false" visibility="public" namespace="m1" xmi.id="82" name="" >
+ <UML:Association.connection>
+ <UML:AssociationEnd isSpecification="false" visibility="public" changeability="changeable" isNavigable="true" xmi.id="83" aggregation="composite" type="40" name="" />
+ <UML:AssociationEnd isSpecification="false" visibility="public" changeability="changeable" isNavigable="true" xmi.id="84" aggregation="none" type="42" name="" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association isSpecification="false" visibility="public" namespace="m1" xmi.id="85" name="" >
+ <UML:Association.connection>
+ <UML:AssociationEnd isSpecification="false" visibility="public" changeability="changeable" isNavigable="true" xmi.id="86" aggregation="composite" type="40" name="" />
+ <UML:AssociationEnd isSpecification="false" visibility="public" changeability="changeable" isNavigable="true" xmi.id="87" aggregation="none" type="43" name="" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association isSpecification="false" visibility="public" namespace="m1" xmi.id="88" name="" >
+ <UML:Association.connection>
+ <UML:AssociationEnd isSpecification="false" visibility="public" changeability="changeable" isNavigable="true" xmi.id="89" aggregation="composite" type="40" name="" />
+ <UML:AssociationEnd isSpecification="false" visibility="public" changeability="changeable" isNavigable="true" xmi.id="90" aggregation="none" type="44" name="" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association isSpecification="false" visibility="public" namespace="m1" xmi.id="91" name="" >
+ <UML:Association.connection>
+ <UML:AssociationEnd isSpecification="false" visibility="public" changeability="changeable" isNavigable="true" xmi.id="92" aggregation="composite" type="40" name="" />
+ <UML:AssociationEnd isSpecification="false" visibility="public" changeability="changeable" isNavigable="true" xmi.id="93" aggregation="none" type="45" name="" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Association isSpecification="false" visibility="public" namespace="m1" xmi.id="94" name="" >
+ <UML:Association.connection>
+ <UML:AssociationEnd isSpecification="false" visibility="public" changeability="changeable" isNavigable="true" xmi.id="95" aggregation="composite" type="40" name="" />
+ <UML:AssociationEnd isSpecification="false" visibility="public" changeability="changeable" isNavigable="true" xmi.id="96" aggregation="none" type="46" name="" />
+ </UML:Association.connection>
+ </UML:Association>
+ <UML:Generalization isSpecification="false" child="48" visibility="public" namespace="m1" xmi.id="107" parent="35" discriminator="" name="" />
+ <UML:Generalization isSpecification="false" child="41" visibility="public" namespace="m1" xmi.id="112" parent="35" discriminator="" name="" />
+ <UML:Generalization isSpecification="false" child="40" visibility="public" namespace="m1" xmi.id="117" parent="35" discriminator="" name="" />
+ </UML:Namespace.ownedElement>
+ </UML:Model>
+ </XMI.content>
+ <XMI.extensions xmi.extender="umbrello" >
+ <docsettings viewid="34" documentation="" uniqueid="135" />
<diagrams>
- <diagram snapgrid="0" showattsig="1" fillcolor="#ffffc0" showgrid="0" showopsig="1" usefillcolor="1" snapx="10" snapy="10" showatts="1" xmi.id="34" documentation="" type="402" showops="1" showpackage="1" name="class diagram" localid="30000" showstereotype="0" showscope="1" font="Clean,11,-1,5,50,0,0,0,1,0" linecolor="#ff0000" >
+ <diagram snapgrid="0" showattsig="1" fillcolor="#ffffc0" linewidth="0" zoom="100" showgrid="0" showopsig="1" usefillcolor="1" snapx="10" canvaswidth="1014" snapy="10" showatts="1" xmi.id="34" documentation="" type="402" showops="1" showpackage="1" name="class diagram" localid="30000" showstereotype="0" showscope="1" snapcsgrid="0" font="Clean,11,-1,5,50,0,0,0,1,0" linecolor="#ff0000" canvasheight="615" >
<widgets>
- <UML:ConceptWidget usesdiagramfillcolour="0" width="443" showattsigs="601" usesdiagramusefillcolour="0" x="99" linecolour="#ff0000" y="66" showopsigs="601" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="45" usefillcolor="1" showattributes="1" xmi.id="35" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Clean,11,-1,5,50,0,0,0,1,0" />
- <UML:ConceptWidget usesdiagramfillcolour="0" width="172" showattsigs="601" usesdiagramusefillcolour="0" x="197" linecolour="#ff0000" y="180" showopsigs="601" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="45" usefillcolor="1" showattributes="1" xmi.id="37" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Clean,11,-1,5,50,0,0,0,1,0" />
- <UML:ConceptWidget usesdiagramfillcolour="0" width="146" showattsigs="601" usesdiagramusefillcolour="0" x="210" linecolour="#ff0000" y="371" showopsigs="601" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="36" usefillcolor="1" showattributes="1" xmi.id="40" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Clean,11,-1,5,50,0,0,0,1,0" />
- <UML:ConceptWidget usesdiagramfillcolour="0" width="227" showattsigs="601" usesdiagramusefillcolour="0" x="658" linecolour="#ff0000" y="184" showopsigs="601" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="36" usefillcolor="1" showattributes="1" xmi.id="41" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Clean,11,-1,5,50,0,0,0,1,0" />
- <UML:ConceptWidget usesdiagramfillcolour="0" width="222" showattsigs="601" usesdiagramusefillcolour="0" x="427" linecolour="#ff0000" y="307" showopsigs="601" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="36" usefillcolor="1" showattributes="1" xmi.id="42" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Clean,11,-1,5,50,0,0,0,1,0" />
- <UML:ConceptWidget usesdiagramfillcolour="0" width="190" showattsigs="601" usesdiagramusefillcolour="0" x="426" linecolour="#ff0000" y="357" showopsigs="601" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="36" usefillcolor="1" showattributes="1" xmi.id="43" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Clean,11,-1,5,50,0,0,0,1,0" />
- <UML:ConceptWidget usesdiagramfillcolour="0" width="220" showattsigs="601" usesdiagramusefillcolour="0" x="427" linecolour="#ff0000" y="411" showopsigs="601" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="36" usefillcolor="1" showattributes="1" xmi.id="44" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Clean,11,-1,5,50,0,0,0,1,0" />
- <UML:ConceptWidget usesdiagramfillcolour="0" width="226" showattsigs="601" usesdiagramusefillcolour="0" x="427" linecolour="#ff0000" y="464" showopsigs="601" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="36" usefillcolor="1" showattributes="1" xmi.id="45" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Clean,11,-1,5,50,0,0,0,1,0" />
- <UML:ConceptWidget usesdiagramfillcolour="0" width="184" showattsigs="601" usesdiagramusefillcolour="0" x="427" linecolour="#ff0000" y="517" showopsigs="601" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="36" usefillcolor="1" showattributes="1" xmi.id="46" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Clean,11,-1,5,50,0,0,0,1,0" />
- <UML:ConceptWidget usesdiagramfillcolour="0" width="147" showattsigs="601" usesdiagramusefillcolour="0" x="24" linecolour="#ff0000" y="320" showopsigs="601" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="36" usefillcolor="1" showattributes="1" xmi.id="47" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Clean,11,-1,5,50,0,0,0,1,0" />
- <UML:ConceptWidget usesdiagramfillcolour="0" width="168" showattsigs="601" usesdiagramusefillcolour="0" x="13" linecolour="#ff0000" y="252" showopsigs="601" usesdiagramlinecolour="0" fillcolour="#ffffc0" height="36" usefillcolor="1" showattributes="1" xmi.id="48" showoperations="1" showpackage="1" showscope="1" showstereotype="0" font="Clean,11,-1,5,50,0,0,0,1,0" />
+ <classwidget usesdiagramfillcolour="0" width="550" showattsigs="601" usesdiagramusefillcolour="0" x="99" y="66" showopsigs="601" linewidth="none" fillcolour="#ffffc0" height="50" usefillcolor="1" showpubliconly="0" showattributes="1" isinstance="0" xmi.id="35" showoperations="1" showpackage="1" showscope="1" font="Clean,11,-1,5,75,0,0,0,1,0" linecolor="#ff0000" />
+ <classwidget usesdiagramfillcolour="0" width="165" showattsigs="601" usesdiagramusefillcolour="0" x="84" y="246" showopsigs="601" linewidth="none" fillcolour="#ffffc0" height="40" usefillcolor="1" showpubliconly="0" showattributes="1" isinstance="0" xmi.id="40" showoperations="1" showpackage="1" showscope="1" font="Clean,11,-1,5,75,0,0,0,1,0" linecolor="#ff0000" />
+ <classwidget usesdiagramfillcolour="0" width="264" showattsigs="601" usesdiagramusefillcolour="0" x="658" y="184" showopsigs="601" linewidth="none" fillcolour="#ffffc0" height="40" usefillcolor="1" showpubliconly="0" showattributes="1" isinstance="0" xmi.id="41" showoperations="1" showpackage="1" showscope="1" font="Clean,11,-1,5,75,0,0,0,1,0" linecolor="#ff0000" />
+ <classwidget usesdiagramfillcolour="0" width="255" showattsigs="601" usesdiagramusefillcolour="0" x="488" y="331" showopsigs="601" linewidth="none" fillcolour="#ffffc0" height="40" usefillcolor="1" showpubliconly="0" showattributes="1" isinstance="0" xmi.id="42" showoperations="1" showpackage="1" showscope="1" font="Clean,11,-1,5,75,0,0,0,1,0" linecolor="#ff0000" />
+ <classwidget usesdiagramfillcolour="0" width="219" showattsigs="601" usesdiagramusefillcolour="0" x="209" y="348" showopsigs="601" linewidth="none" fillcolour="#ffffc0" height="40" usefillcolor="1" showpubliconly="0" showattributes="1" isinstance="0" xmi.id="43" showoperations="1" showpackage="1" showscope="1" font="Clean,11,-1,5,75,0,0,0,1,0" linecolor="#ff0000" />
+ <classwidget usesdiagramfillcolour="0" width="255" showattsigs="601" usesdiagramusefillcolour="0" x="154" y="399" showopsigs="601" linewidth="none" fillcolour="#ffffc0" height="40" usefillcolor="1" showpubliconly="0" showattributes="1" isinstance="0" xmi.id="44" showoperations="1" showpackage="1" showscope="1" font="Clean,11,-1,5,75,0,0,0,1,0" linecolor="#ff0000" />
+ <classwidget usesdiagramfillcolour="0" width="264" showattsigs="601" usesdiagramusefillcolour="0" x="54" y="449" showopsigs="601" linewidth="none" fillcolour="#ffffc0" height="40" usefillcolor="1" showpubliconly="0" showattributes="1" isinstance="0" xmi.id="45" showoperations="1" showpackage="1" showscope="1" font="Clean,11,-1,5,75,0,0,0,1,0" linecolor="#ff0000" />
+ <classwidget usesdiagramfillcolour="0" width="201" showattsigs="601" usesdiagramusefillcolour="0" x="42" y="512" showopsigs="601" linewidth="none" fillcolour="#ffffc0" height="40" usefillcolor="1" showpubliconly="0" showattributes="1" isinstance="0" xmi.id="46" showoperations="1" showpackage="1" showscope="1" font="Clean,11,-1,5,75,0,0,0,1,0" linecolor="#ff0000" />
</widgets>
<messages/>
<associations>
- <UML:AssocWidget totalcounta="4" indexa="2" totalcountb="2" indexb="1" widgetbid="37" widgetaid="40" documentation="" type="500" >
+ <assocwidget totalcounta="3" indexa="2" totalcountb="2" indexb="1" linewidth="none" widgetbid="41" widgetaid="42" xmi.id="67" linecolor="none" >
<linepath>
- <startpoint startx="283" starty="371" />
- <endpoint endx="283" endy="225" />
+ <startpoint startx="658" starty="331" />
+ <endpoint endx="790" endy="224" />
</linepath>
- </UML:AssocWidget>
- <UML:AssocWidget totalcounta="2" indexa="1" totalcountb="2" indexb="1" widgetbid="37" widgetaid="41" documentation="" type="500" >
+ </assocwidget>
+ <assocwidget totalcounta="5" indexa="1" totalcountb="3" indexb="1" linewidth="none" widgetbid="40" widgetaid="35" xmi.id="70" linecolor="none" >
<linepath>
- <startpoint startx="658" starty="202" />
- <endpoint endx="369" endy="202" />
+ <startpoint startx="209" starty="116" />
+ <endpoint endx="139" endy="246" />
</linepath>
- </UML:AssocWidget>
- <UML:AssocWidget totalcounta="2" indexa="1" totalcountb="2" indexb="1" widgetbid="41" widgetaid="42" documentation="" type="500" >
+ </assocwidget>
+ <assocwidget totalcounta="5" indexa="3" totalcountb="3" indexb="1" linewidth="none" widgetbid="41" widgetaid="35" xmi.id="73" linecolor="none" >
<linepath>
- <startpoint startx="538" starty="307" />
- <endpoint endx="771" endy="220" />
+ <startpoint startx="429" starty="116" />
+ <endpoint endx="746" endy="184" />
</linepath>
- </UML:AssocWidget>
- <UML:AssocWidget totalcounta="3" indexa="1" totalcountb="4" indexb="1" widgetbid="40" widgetaid="35" documentation="" type="512" >
+ </assocwidget>
+ <assocwidget totalcounta="2" indexa="1" totalcountb="3" indexb="1" linewidth="none" widgetbid="42" widgetaid="40" xmi.id="82" linecolor="none" >
<linepath>
- <startpoint startx="246" starty="111" />
- <endpoint endx="246" endy="371" />
+ <startpoint startx="249" starty="266" />
+ <endpoint endx="573" endy="331" />
</linepath>
- </UML:AssocWidget>
- <UML:AssocWidget totalcounta="3" indexa="2" totalcountb="2" indexb="1" widgetbid="41" widgetaid="35" documentation="" type="512" >
+ </assocwidget>
+ <assocwidget totalcounta="5" indexa="4" totalcountb="2" indexb="1" linewidth="none" widgetbid="43" widgetaid="40" xmi.id="85" linecolor="none" >
<linepath>
- <startpoint startx="394" starty="111" />
- <endpoint endx="771" endy="184" />
+ <startpoint startx="216" starty="286" />
+ <endpoint endx="318" endy="348" />
</linepath>
- </UML:AssocWidget>
- <UML:AssocWidget totalcounta="2" indexa="1" totalcountb="2" indexb="1" widgetbid="37" widgetaid="48" documentation="" type="500" >
+ </assocwidget>
+ <assocwidget totalcounta="5" indexa="3" totalcountb="2" indexb="1" linewidth="none" widgetbid="44" widgetaid="40" xmi.id="88" linecolor="none" >
<linepath>
- <startpoint startx="97" starty="252" />
- <endpoint endx="197" endy="202" />
+ <startpoint startx="183" starty="286" />
+ <endpoint endx="281" endy="399" />
</linepath>
- </UML:AssocWidget>
- <UML:AssocWidget totalcounta="2" indexa="1" totalcountb="2" indexb="1" widgetbid="48" widgetaid="47" documentation="" type="500" >
+ </assocwidget>
+ <assocwidget totalcounta="5" indexa="2" totalcountb="2" indexb="1" linewidth="none" widgetbid="45" widgetaid="40" xmi.id="91" linecolor="none" >
<linepath>
- <startpoint startx="97" starty="320" />
- <endpoint endx="97" endy="288" />
+ <startpoint startx="150" starty="286" />
+ <endpoint endx="186" endy="449" />
</linepath>
- </UML:AssocWidget>
- <UML:AssocWidget totalcounta="2" indexa="1" totalcountb="4" indexb="3" widgetbid="40" widgetaid="42" documentation="" type="510" >
+ </assocwidget>
+ <assocwidget totalcounta="5" indexa="1" totalcountb="2" indexb="1" linewidth="none" widgetbid="46" widgetaid="40" xmi.id="94" linecolor="none" >
<linepath>
- <startpoint startx="427" starty="325" />
- <endpoint endx="319" endy="371" />
+ <startpoint startx="117" starty="286" />
+ <endpoint endx="142" endy="512" />
</linepath>
- </UML:AssocWidget>
- <UML:AssocWidget totalcounta="2" indexa="1" totalcountb="3" indexb="1" widgetbid="40" widgetaid="43" documentation="" type="510" >
+ </assocwidget>
+ <assocwidget totalcounta="3" indexa="2" totalcountb="5" indexb="4" linewidth="none" widgetbid="35" widgetaid="41" xmi.id="112" linecolor="none" >
<linepath>
- <startpoint startx="426" starty="375" />
- <endpoint endx="356" endy="383" />
+ <startpoint startx="834" starty="184" />
+ <endpoint endx="539" endy="116" />
</linepath>
- </UML:AssocWidget>
- <UML:AssocWidget totalcounta="2" indexa="1" totalcountb="3" indexb="2" widgetbid="40" widgetaid="44" documentation="" type="510" >
+ </assocwidget>
+ <assocwidget totalcounta="3" indexa="2" totalcountb="5" indexb="2" linewidth="none" widgetbid="35" widgetaid="40" xmi.id="117" linecolor="none" >
<linepath>
- <startpoint startx="537" starty="411" />
- <endpoint endx="356" endy="395" />
+ <startpoint startx="194" starty="246" />
+ <endpoint endx="319" endy="116" />
</linepath>
- </UML:AssocWidget>
- <UML:AssocWidget totalcounta="2" indexa="1" totalcountb="3" indexb="1" widgetbid="40" widgetaid="45" documentation="" type="510" >
- <linepath>
- <startpoint startx="540" starty="464" />
- <endpoint endx="258" endy="407" />
- </linepath>
- </UML:AssocWidget>
- <UML:AssocWidget totalcounta="2" indexa="1" totalcountb="3" indexb="2" widgetbid="40" widgetaid="46" documentation="" type="510" >
- <linepath>
- <startpoint startx="519" starty="517" />
- <endpoint endx="307" endy="407" />
- </linepath>
- </UML:AssocWidget>
+ </assocwidget>
</associations>
</diagram>
</diagrams>
<listview>
- <listitem open="1" type="800" id="-1" label="Views" >
- <listitem open="1" type="801" id="-1" label="Logical View" >
- <listitem open="1" type="813" id="35" label="Tree" >
- <listitem open="0" type="815" id="36" label="setup" />
+ <listitem open="1" type="800" label="Views" >
+ <listitem open="1" type="801" label="Logical View" >
+ <listitem open="1" type="813" id="35" >
+ <listitem open="0" type="815" id="36" />
</listitem>
- <listitem open="1" type="813" id="37" label="Tree_Common" >
- <listitem open="0" type="814" id="38" label="options" />
+ <listitem open="1" type="813" id="37" >
+ <listitem open="0" type="814" id="38" />
</listitem>
- <listitem open="1" type="813" id="41" label="Tree_Dynamic_DBnested" />
- <listitem open="1" type="813" id="40" label="Tree_Memory" />
- <listitem open="1" type="813" id="43" label="Tree_Memory_Array" />
- <listitem open="1" type="813" id="42" label="Tree_Memory_DBnested" />
- <listitem open="1" type="813" id="44" label="Tree_Memory_DBsimple" />
- <listitem open="1" type="813" id="45" label="Tree_Memory_Filesystem" />
- <listitem open="1" type="813" id="46" label="Tree_Memory_XML" />
- <listitem open="1" type="813" id="47" label="Tree_Options" />
- <listitem open="1" type="813" id="48" label="Tree_OptionsDB" />
- <listitem open="0" type="807" id="34" label="class diagram" />
+ <listitem open="1" type="813" id="41" />
+ <listitem open="1" type="813" id="40" />
+ <listitem open="1" type="813" id="43" />
+ <listitem open="1" type="813" id="42" />
+ <listitem open="1" type="813" id="44" />
+ <listitem open="1" type="813" id="45" />
+ <listitem open="1" type="813" id="46" />
+ <listitem open="1" type="813" id="47" />
+ <listitem open="1" type="813" id="48" />
+ <listitem open="0" type="813" id="99" />
+ <listitem open="0" type="813" id="98" />
+ <listitem open="0" type="813" id="97" />
+ <listitem open="0" type="818" id="50" />
+ <listitem open="0" type="830" label="Datatypes" />
</listitem>
- <listitem open="1" type="802" id="-1" label="Use Case View" />
+ <listitem open="1" type="802" label="Use Case View" />
+ <listitem open="1" type="821" label="Component View" />
+ <listitem open="1" type="827" label="Deployment View" />
+ <listitem open="1" type="836" label="Entity Relationship Model" />
</listitem>
</listview>
- </XMI.content>
+ <codegeneration>
+ <codegenerator language="SQL" />
+ </codegeneration>
+ </XMI.extensions>
</XMI>
Property changes on: docs/umbrello-uml.xmi
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.1
+1.2
Index: docs/Memory_DBsimple.php
===================================================================
--- docs/Memory_DBsimple.php (.../branches/Tree_0_3_0) (revision 321102)
+++ docs/Memory_DBsimple.php (.../trunk) (revision 321102)
@@ -1,63 +1,16 @@
<?php
- //
- // $Id$
- //
+// $Id$
-//ini_set('include_path',realpath(dirname(__FILE__).'/../../').':'.realpath(dirname(__FILE__).'/../../../includes').':'.ini_get('include_path'));
-//ini_set('error_reporting',E_ALL);
+include_once 'funcs.php';
- /**
- * this is a helper function, so i dont have to write so many prints :-)
- * @param array $para the result returned by some method, that will be dumped
- * @param string $string the explaining string
- */
- function dumpHelper($para, $string = '', $addArray = false)
- {
- global $tree,$element;
- if ($addArray) {
- eval("\$res=array(".$para.');');
- } else {
- eval("\$res=".$para.';');
- }
- echo '<b>' . $para . ' </b><i><u><font color="#008000">' . $string . '</font></u></i><br>';
- // this method dumps to the screen, since print_r or var_dump dont
- // work too good here, because the inner array is recursive
- // well, it looks ugly but one can see what is meant :-)
- $tree->varDump($res);
- echo '<br>';
-
- }
-
- /**
- * dumps the entire structure nicely
- * @param string $string the explaining string
- */
- function dumpAllNicely($string = '')
- {
- global $tree;
-
- echo '<i><u><font color="#008000">' . $string . '</font></u></i><br>';
- $all = $tree->getNode(); // get the entire structure sorted as the tree is, so we can simply foreach through it and show it
- foreach($all as $aElement) {
- for ($i = 0; $i < $aElement['level']; $i++) {
- echo '&nbsp; &nbsp; ';
- }
- echo $aElement['name'].' ===&gt; ';
- $tree->varDump(array($aElement));
- }
- echo '<br>';
-
- }
-
-
/*
use this to build the db table
CREATE TABLE test_tree (
id int(11) NOT NULL auto_increment,
- parentId int(11) NOT NULL default '0',
+ parent int(11) NOT NULL default '0',
name varchar(255) NOT NULL default '',
PRIMARY KEY (id)
)
@@ -78,30 +31,39 @@
require_once 'Tree/Tree.php';
// define the DB-table where the data shall be read from
- $options = array('table' => 'test_tree',
- 'order' => 'id' // when reading the data from the db sort them by id, this is only for ensuring
- // for 'getNext' of "myElement/subElement" in this example to find "myElement/anotherSubElement"
- // you can simply sort it by "name" and it would be in alphabetical order
- );
-
+ // when reading the data from the db sort them by id, this is only for ensuring
+ // for 'getNext' of "myElement/subElement" in this example to find "myElement/anotherSubElement"
+ // you can simply sort it by "name" and it would be in alphabetical order
// calling 'setupMemory' means to retreive a class, which works on trees,
// that are temporarily stored in the memory, in an array
// this means the entire tree is available at all time
// consider the resource usage and it's not to suggested to work
// on huge trees (upto 1000 elements it should be ok, depending on your environment and requirements)
// using 'setupMemory'
- $tree = Tree::setupMemory('DBsimple', // use the simple DB schema
- 'mysql://root@localhost/tree_test', // the DSN
- $options); // pass the options we had assigned up there
+ $config = array(
+ 'type' => 'Simple',
+ 'storage' => array(
+ 'name' => 'DB',
+ 'dsn' => 'mysql://root:hamstur@localhost/tree_test',
+ // 'connection' => $db,
+ ),
+ 'options' => array(
+ 'table' => 'test_tree',
+ 'order' => 'id',
+ 'fields' => array(),
+ ),
+ );
+ $tree =& Tree::factoryMemory($config);
+
// add a new root element in the tree
$parentId = $tree->add(array('name' => 'myElement'));
// add an element under the new element we added
- $id = $tree->add(array('name' => 'subElement') , $parentId );
+ $id = $tree->add(array('name' => 'subElement'), $parentId);
// add another element under the parent element we added
- $id = $tree->add(array('name' => 'anotherSubElement') , $parentId );
+ $id = $tree->add(array('name' => 'anotherSubElement'), $parentId);
// call 'setup', to build the inner array, so we can work on the structure using the
// given methods
@@ -117,7 +79,7 @@
// you can also use: $tree->data[$id]['parent']
$id = $tree->getIdByPath('myElement');
- dumpHelper('$tree->getChild('.$id.')' , 'dump the child of "myElement"' , true);
+ dumpHelper('$tree->getChildren('.$id.', true)' , 'dump the child of "myElement"' , true);
// you can also use: $tree->data[$id]['child']
$id = $tree->getIdByPath('myElement');
@@ -125,21 +87,13 @@
// you can also use: $tree->data[$id]['children']
$id = $tree->getIdByPath('myElement/subElement');
- dumpHelper('$tree->getNext('.$id.')' , 'dump the "next" of "myElement/subElement"' , true);
+ dumpHelper('$tree->nextSibling('.$id.')' , 'dump the "next" of "myElement/subElement"' , true);
// you can also use: $tree->data[$id]['next']
$id = $tree->getIdByPath('myElement/anotherSubElement');
- dumpHelper('$tree->getPrevious('.$id.')' , 'dump the "previous" of "myElement/anotherSubElement"' , true);
+ dumpHelper('$tree->prevSibling('.$id.')' , 'dump the "previous" of "myElement/anotherSubElement"' , true);
// you can also use: $tree->data[$id]['previous']
- $id = $tree->getIdByPath('myElement');
- $element = $tree->data[$id]['child']['next']['parent']; // refer to yourself again, in a very complicated way :-)
- dumpHelper('$element[\'id\']' , 'demo of using the internal array, for referencing tree-nodes, see the code');
-
- $id = $tree->getIdByPath('myElement');
- $element = $tree->data[$id]['child']['next']; // refer to the second child of 'myElement'
- dumpHelper('$element[\'id\']' , 'demo2 of using the internal array, for referencing tree-nodes, see the code');
-
$id = $tree->getIdByPath('myElement/anotherSubElement');
$tree->move($id , 0);
$tree->setup(); // rebuild the structure again, since we had changed it
@@ -147,12 +101,12 @@
$moveId = $tree->getIdByPath('myElement');
$id = $tree->getIdByPath('anotherSubElement');
- $tree->move( $moveId , $id );
- $tree->setup(); // rebuild the structure again, since we had changed it
+ #$tree->move( $moveId , $id );
+ #$tree->setup(); // rebuild the structure again, since we had changed it
dumpAllNicely('dump all, after "myElement" was moved under the "anotherSubElement"');
- $tree->setRemoveRecursively(true);
- $tree->remove(0);
- echo '<font color="red">ALL ELEMENTS HAVE BEEN REMOVED (uncomment this part to keep them in the DB after running this test script)</font>';
+ #$tree->setRemoveRecursively(true);
+ #$tree->remove(0);
+ #echo '<font color="red">ALL ELEMENTS HAVE BEEN REMOVED (uncomment this part to keep them in the DB after running this test script)</font>';
?>
Property changes on: docs/Memory_DBsimple.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.3
+1.4
Index: docs/Memory_XML.php
===================================================================
--- docs/Memory_XML.php (.../branches/Tree_0_3_0) (revision 321102)
+++ docs/Memory_XML.php (.../trunk) (revision 321102)
@@ -1,10 +1,7 @@
<?php
- //
- // $Id$
- //
+// $Id$
-//ini_set('include_path',realpath(dirname(__FILE__).'/../../').':'.realpath(dirname(__FILE__).'/../../../includes').':'.ini_get('include_path'));
-//ini_set('error_reporting',E_ALL);
+ini_set('error_reporting', E_ALL);
/**
* this is a helper function, so i dont have to write so many prints :-)
* @param array $para the result returned by some method, that will be dumped
@@ -14,12 +11,12 @@
{
global $tree;
- echo'<i><u><font color="#008000">' . $string . '</font></u></i><br>';
+ echo'<i><u><span style="color: #008000;">' . $string . '</span></u></i><br />';
// this method dumps to the screen, since print_r or var_dump dont
// work too good here, because the inner array is recursive
// well, it looks ugly but one can see what is meant :-)
$tree->varDump($para);
- echo '<br>';
+ echo '<br />';
}
@@ -31,7 +28,7 @@
{
global $tree;
- echo '<i><u><font color="#008000">' . $string . '</font></u></i><br>';
+ echo '<i><u><span style="color: #008000;">' . $string . '</span></u></i><br />';
$all = $tree->getNode(); // get the entire structure sorted as the tree is, so we can simply foreach through it and show it
foreach ($all as $aElement) {
for ($i = 0; $i < $aElement['level']; $i++) {
@@ -45,10 +42,10 @@
echo 'attributes - ';
print_r($aElement['attributes']);
- echo '<br>';
+ echo '<br />';
}
- echo '<br>';
+ echo '<br />';
}
@@ -80,10 +77,18 @@
// consider the resource usage and it's not to suggested to work
// on huge trees (upto 1000 elements it should be ok, depending on your environment and requirements)
// using 'setupMemory'
- $tree = Tree::setupMemory('XML', // use the XML class to read an xml file
- 'config.xml' // the DSN
- );
+ $config = array(
+ 'type' => '',
+ 'storage' => array(
+ 'name' => 'XML',
+ 'dsn' => 'config.xml',
+ ),
+ 'options' => array(
+ ),
+ );
+ $tree =& Tree::factoryMemory($config);
+
// methods 'add' 'remove' and so on are not implemented yet, you can only read the tree for now
// and navigate inside of it
@@ -95,10 +100,10 @@
// get the path of the last inserted element
echo 'id='.$id = $tree->getIdByPath('simpletemplate/options/delimiter');
- dumpHelper( $tree->getPath( $id ) , 'dump the path from "simpletemplate/options/delimiter"');
+ dumpHelper( $tree->getPath($id), 'dump the path from "simpletemplate/options/delimiter"');
$id = $tree->getIdByPath('simpletemplate/options');
- dumpHelper(array($tree->getParent($id)) , 'dump the parent of "simpletemplate/options"');
+ dumpHelper(array($tree->getParent($id)), 'dump the parent of "simpletemplate/options"');
// you can also use: $tree->data[$id]['parent']
$id = $tree->getIdByPath('simpletemplate');
@@ -106,15 +111,15 @@
// you can also use: $tree->data[$id]['child']
$id = $tree->getIdByPath('simpletemplate/prefilter');
- dumpHelper($tree->getChildren($id) , 'dump the children of "simpletemplate/prefilter"');
+ dumpHelper($tree->getChildren($id), 'dump the children of "simpletemplate/prefilter"');
// you can also use: $tree->data[$id]['children']
$id = $tree->getIdByPath('simpletemplate/options');
- dumpHelper(array($tree->getNext($id)) , 'dump the "next" of "simpletemplate/options"');
+ dumpHelper(array($tree->getNext($id)), 'dump the "next" of "simpletemplate/options"');
// you can also use: $tree->data[$id]['next']
$id = $tree->getIdByPath('simpletemplate/prefilter');
- dumpHelper( array($tree->getPrevious($id)) , 'dump the "previous" of "simpletemplate/prefilter"');
+ dumpHelper(array($tree->getPrevious($id)), 'dump the "previous" of "simpletemplate/prefilter"');
// you can also use: $tree->data[$id]['previous']
@@ -123,18 +128,18 @@
dumpHelper($element['id'] , 'demo of using the internal array, for referencing tree-nodes');
/*
-NOT IMPLEMENTED YET
+ NOT IMPLEMENTED YET
$id = $tree->getIdByPath('myElement/anotherSubElement');
- $tree->move( $id , 0 );
+ $tree->move($id, 0);
$tree->setup(); // rebuild the structure again, since we had changed it
- dumpAllNicely( 'dump all, after "myElement/anotherSubElement" was moved under the root' );
+ dumpAllNicely('dump all, after "myElement/anotherSubElement" was moved under the root');
$moveId = $tree->getIdByPath('myElement');
$id = $tree->getIdByPath('anotherSubElement');
- $tree->move( $moveId , $id );
+ $tree->move($moveId, $id);
$tree->setup(); // rebuild the structure again, since we had changed it
- dumpAllNicely( 'dump all, after "myElement" was moved under the "anotherSubElement"' );
+ dumpAllNicely('dump all, after "myElement" was moved under the "anotherSubElement"');
$tree->setRemoveRecursively(true);
Property changes on: docs/Memory_XML.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.3
+1.4
Index: package.xml
===================================================================
--- package.xml (.../branches/Tree_0_3_0) (revision 321102)
+++ package.xml (.../trunk) (revision 321102)
@@ -5,38 +5,26 @@
http://pear.php.net/dtd/package-2.0.xsd">
<name>Tree</name>
<channel>pear.php.net</channel>
- <summary>Generic tree management, currently supports databases (via DB, MDB and MDB2) and XML as data sources</summary>
- <description>Provides methods to read and manipulate trees, which are stored in a database (via DB, MDB and MDB2) or an XML file.
-
-The trees can be stored in the DB either as nested trees.
-Or as simple trees, which use parentId-like structure.
+ <summary>Generic tree management, currently supports DB, MDB and XML as data sources</summary>
+ <description>Provides methods to read and manipulate trees, which are stored in the DB/MDB
+or an XML file. The trees can be stored in the DB either as nested trees.
+Or as simple trees (&apos;brain dead method&apos;), which use parentId-like structure.
Currently XML data can only be read from a file and accessed.
The package offers a big number of methods to access and manipulate trees.
For example methods like: getRoot, getChild[ren[Ids]], getParent[s[Ids]], getPath[ById] and many
more.
-
There are two ways of retreiving the data from the place where they are stored,
one is by reading the entire tree into the memory - the Memory way. The other
is reading the tree nodes as needed (very useful in combination with huge trees
and the nested set model).
-
The package is designed that way that it is possible to convert/copy tree data
-from either structure to another (from XML into DB).
-
-
-This package has the following drivers:
-* DB
-* MDB
-* MDB2
-* Array
-* XML
-* FileSystem
+from either structure to another (from XML into DB/MDB).
</description>
<lead>
<name>Wolfram Kriesing</name>
<user>cain</user>
<email>wolfram@kriesing.de</email>
- <active>no</active>
+ <active>yes</active>
</lead>
<lead>
<name>Helgi Þormar</name>
@@ -44,52 +32,65 @@
<email>helgi@trance.is</email>
<active>yes</active>
</lead>
- <lead>
- <name>Daniel Convissor</name>
- <user>danielc</user>
- <email>danielc@php.net</email>
- <active>no</active>
- </lead>
- <date>2011-12-09</date>
+ <date>2007-06-02</date>
+ <time>00:25:37</time>
<version>
- <release>0.3.5</release>
- <api>0.3.5</api>
+ <release>0.4.0</release>
+ <api>0.4.0</api>
</version>
<stability>
<release>beta</release>
<api>beta</api>
</stability>
<license uri="http://www.php.net/license">PHP License</license>
- <notes>
-* Fixed Bug 19119 Only variable references should be returned by reference.
+ <notes>This is a rewrite of Tree so there are BC breaks! Please look at the examples to see how things are done now.
+* add unit test, at least for all new/modified methods
+* setup* in Tree.php renamed to factory*
+* Configurations rewritten, look at examples to see how it&apos;s done now.
+* From now on changing anything in regards to fields can not be done via setOption.
+* Removed these functions in Common.php
+ - getNextId
+ - getPreviousId
+ - getLeftId
+ - getRightId
+ - getFirstRootId
+ - getRootId
+ - getChildId
+* Common.php merged with Tree.php
+* From now one use $foo = $tree-&gt;getParent(); echo $foo[&apos;id&apos;]; to get the same effect as getParentId().
+ Note, that&apos;s just what getParentId did, we just removed the extra wrapper around it this way.
+* removed buildStructure, most of it&apos;s functionallity has been merged with _setup, and
+ the structure array is no longer multi dimensional
+* getNext renamed to nextSibling and getPrevious renamed to previousSibling to describe their functionality better
+* OptionsMDB.php and OptionsDB.php removed
+* getChild removed, use getChildren($id, true) instead (note, $oneChild is a new param so $levels has been moved back)
+ the signature is now: function getChildren($ids, $levels = 1, $oneChild = false)
+* getNode renamed to getBranch to reflect it&apos;s purpose better
+
</notes>
<contents>
<dir name="/">
<dir name="Tree">
<dir name="Dynamic">
- <file baseinstalldir="Tree" name="DBnested.php" role="php" />
- <file baseinstalldir="Tree" name="MDBnested.php" role="php" />
- <file baseinstalldir="Tree" name="MDB2nested.php" role="php" />
+ <file baseinstalldir="Tree" name="SQLnested.php" role="php" />
</dir> <!-- /Dynamic -->
<dir name="Memory">
<file baseinstalldir="Tree" name="Array.php" role="php" />
- <file baseinstalldir="Tree" name="DBnested.php" role="php" />
- <file baseinstalldir="Tree" name="DBsimple.php" role="php" />
- <file baseinstalldir="Tree" name="MDBnested.php" role="php" />
- <file baseinstalldir="Tree" name="MDBsimple.php" role="php" />
- <file baseinstalldir="Tree" name="MDB2nested.php" role="php" />
- <file baseinstalldir="Tree" name="MDB2simple.php" role="php" />
<file baseinstalldir="Tree" name="Filesystem.php" role="php" />
+ <file baseinstalldir="Tree" name="SQLnested.php" role="php" />
+ <file baseinstalldir="Tree" name="SQLsimple.php" role="php" />
<file baseinstalldir="Tree" name="XML.php" role="php" />
</dir> <!-- /Memory -->
- <file baseinstalldir="Tree" name="Common.php" role="php" />
- <file baseinstalldir="Tree" name="Error.php" role="php" />
+ <dir name="Storage">
+ <file baseinstalldir="Tree" name="DB.php" role="php" />
+ <file baseinstalldir="Tree" name="MDB.php" role="php" />
+ <file baseinstalldir="Tree" name="MDB2.php" role="php" />
+ <file baseinstalldir="Tree" name="SQL.php" role="php" />
+ </dir> <!-- /Storage -->
<file baseinstalldir="Tree" name="Memory.php" role="php" />
- <file baseinstalldir="Tree" name="OptionsDB.php" role="php" />
- <file baseinstalldir="Tree" name="OptionsMDB.php" role="php" />
- <file baseinstalldir="Tree" name="OptionsMDB2.php" role="php" />
+ <file baseinstalldir="Tree" name="Storage.php" role="php" />
<file baseinstalldir="Tree" name="Tree.php" role="php" />
- </dir> <!-- Tree -->
+ </dir> <!-- /Tree -->
<dir name="docs">
<dir name="TreeEditor">
<file baseinstalldir="Tree" name="closedFolder.gif" role="doc" />
@@ -111,13 +112,14 @@
</dir> <!-- /docs/TreeView -->
<file baseinstalldir="Tree" name="config.xml" role="doc" />
<file baseinstalldir="Tree" name="Dynamic_DBnested.php" role="doc" />
- <file baseinstalldir="Tree" name="Dynamic_DBnested.sql" role="doc" />
+ <file baseinstalldir="Tree" name="Dynamic_MDBnested.php" role="doc" />
+ <file baseinstalldir="Tree" name="funcs.php" role="doc" />
<file baseinstalldir="Tree" name="Memory_DBnested.php" role="doc" />
<file baseinstalldir="Tree" name="Memory_DBsimple.php" role="doc" />
- <file baseinstalldir="Tree" name="Dynamic_MDBnested.php" role="doc" />
<file baseinstalldir="Tree" name="Memory_MDBnested.php" role="doc" />
<file baseinstalldir="Tree" name="Memory_MDBsimple.php" role="doc" />
<file baseinstalldir="Tree" name="Memory_XML.php" role="doc" />
+ <file baseinstalldir="Tree" name="nested_tree.sql" role="doc" />
</dir> <!-- /docs -->
<dir name="tests">
<file baseinstalldir="Tree" name="AllTests.php" role="test" />
@@ -162,102 +164,9 @@
</optional>
</dependencies>
<phprelease />
-
<changelog>
-
<release>
- <date>2009-03-12</date>
- <time>14:12:08</time>
- <version>
- <release>0.3.4</release>
- <api>0.3.4</api>
- </version>
- <stability>
- <release>beta</release>
- <api>beta</api>
- </stability>
- <license uri="http://www.php.net/license">PHP License</license>
- <notes>
-* Fix Bug #14710: trailing spaces in files [dufuz]
- </notes>
- </release>
-
- <release>
- <date>2008-03-23</date>
- <time>14:12:08</time>
- <version>
- <release>0.3.3</release>
- <api>0.3.3</api>
- </version>
- <stability>
- <release>beta</release>
- <api>beta</api>
- </stability>
- <license uri="http://www.php.net/license">PHP License</license>
- <notes>
- * Fixed Bug #11822 package description should include mention of MDB2 compatibility
- * Fixed Bug #11853 Dynamic_MDB2nested uses undefined functions
- * Fixed Bug #12780 DB connection instead DSN fails because of get_parent_class
- * Fixed Bug #13080 MDB2simple _setup(): parentId cleared if parentId column is mapped to "parentid"
- * Fixed Bug #13081 Reopen #11504: MDB2+Tree problem. MDB2 doesn't contains getTextValue method
- </notes>
- </release>
-
- <release>
- <date>2008-03-23</date>
- <time>14:12:08</time>
- <version>
- <release>0.3.3</release>
- <api>0.3.3</api>
- </version>
- <stability>
- <release>beta</release>
- <api>beta</api>
- </stability>
- <license uri="http://www.php.net/license">PHP License</license>
- <notes>
- * Fixed Bug #11822 package description should include mention of MDB2 compatibility
- * Fixed Bug #11853 Dynamic_MDB2nested uses undefined functions
- * Fixed Bug #12780 DB connection instead DSN fails because of get_parent_class
- * Fixed Bug #13080 MDB2simple _setup(): parentId cleared if parentId column is mapped to "parentid"
- * Fixed Bug #13081 Reopen #11504: MDB2+Tree problem. MDB2 doesn't contains getTextValue method
- </notes>
- </release>
- <release>
- <date>2007-08-11</date>
- <time>14:12:08</time>
- <version>
- <release>0.3.2</release>
- <api>0.3.2</api>
- </version>
- <stability>
- <release>beta</release>
- <api>beta</api>
- </stability>
- <license uri="http://www.php.net/license">PHP License</license>
- <notes>
- * Fix Bug #11504 MDB2+Tree problem. MDB2 doesn't contains getTextValue method, patch by Simon Ruderich
- * Fix Bug #11500 Tree/Memory.php method getElementContent() not working, patch by Simon Ruderich
- </notes>
- </release>
- <release>
- <date>2007-06-23</date>
- <time>14:12:08</time>
- <version>
- <release>0.3.2</release>
- <api>0.3.2</api>
- </version>
- <stability>
- <release>beta</release>
- <api>beta</api>
- </stability>
- <license uri="http://www.php.net/license">PHP License</license>
- <notes>
-* Fix Bug #11365 Tree class doesnt contains raiseError method
- </notes>
- </release>
- <release>
- <date>2007-06-02</date>
+<date>2007-06-02</date>
<time>14:12:08</time>
<version>
<release>0.3.0</release>
@@ -272,7 +181,7 @@
* added parameter to getPathAsString(), which takes the key you want to have in the path
* add method getLevel() to Tree_Common, so it is also available for Dynamic_*, thanks to Michael Johnson
* Fixed bug #1976 Missing $this-&gt; with __construct() (helgi)
-* Fixed bug #900 PEAR QA: improvement for get_class()-usage (helgi)
+* Fixed bug #900 PEAR QA: improvement for get_class()-usage (helgi)
* Fixed Bug #913 MDB Container + fixes (lorzenzo thanks! helgi)
* Fixed Bug #1569 Tree_Memory_DBsimple has no hasChildren function hence remove doesnt work (helgi)
* Fixed Bug #4803 References fix (patch from yunosh aka. Jan Schneider)
@@ -280,7 +189,7 @@
* add unit test, at least for all new/modified methods
* CS fixes
* package xml version 2
-
+
</notes>
</release>
<release>
@@ -295,7 +204,7 @@
<date>2003-03-17</date>
<license uri="http://www.php.net/license">PHP License</license>
<notes>* bugfix in Memory_Array::add method, which made the last element being added in a bogus way
-
+
</notes>
</release>
<release>
@@ -326,7 +235,7 @@
* Make setup work with custom data optionally (only relevant for Memory_*)
* Show a nicer varDump
* add UML class diagram
-
+
</notes>
</release>
<release>
Property changes on: package.xml
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.36.2.9
+1.37
Index: .
===================================================================
--- . (.../branches/Tree_0_3_0) (revision 321102)
+++ . (.../trunk) (revision 321102)
Property changes on: .
___________________________________________________________________
Deleted: svn:mergeinfo
Reverse-merged /pear/packages/Tree/trunk:r320621-320622
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment