| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409 |
- <?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: DBsimple.php,v 1.11 2003/01/18 15:36:50 cain Exp $
- 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 optionsDB for now, may be use "aggregate" function to fix that
- {
- /**
- * @access public
- * @var array saves the options passed to the constructor
- */
- var $options = array( '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)
- 'table' =>'', //
- // 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(
- /* '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;
- /**
- * 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');
- } // end of function
- /**
- * 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;
- }
- /**
- * 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;
- } // end of function
- /**
- * 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;
- } // end of function
- /**
- * 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;
- } // end of function
- /**
- * 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;
- } // end of function
- /**
- *
- *
- * @access private
- * @version 2002/03/02
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param
- * @return
- */
- function _throwError( $msg , $line , $mode=null )
- {
- return new Tree_Error( $msg , $line , __FILE__ , $mode , $this->db->last_query );
- }
- /**
- * prepare multiple results
- *
- * @see _prepareResult()
- * @access private
- * @version 2002/03/03
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param
- * @return
- */
- function _prepareResults( $results )
- {
- $newResults = array();
- foreach( $results as $aResult )
- $newResults[] = $this->_prepareResult($aResult);
- return $newResults;
- }
- /**
- * map back the index names to get what is expected
- *
- * @access private
- * @version 2002/03/03
- * @author Wolfram Kriesing <wolfram@kriesing.de>
- * @param
- * @return
- */
- function _prepareResult( $result )
- {
- $map = $this->getOption('columnNameMaps');
- if( $map )
- foreach( $map as $key=>$columnName )
- {
- $result[$key] = $result[$columnName];
- unset($result[$columnName]);
- }
- return $result;
- }
- /**
- * 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>
- * @param
- * @return
- */
- function _getColName( $internalName )
- {
- if( $map = $this->getOption( 'columnNameMaps' ) )
- {
- if( isset($map[$internalName]) )
- return $map[$internalName];
- }
- return $internalName;
- }
- } // end of class
- ?>
|