1 |
joko |
1.1 |
<?php |
2 |
|
|
// |
3 |
|
|
// +----------------------------------------------------------------------+ |
4 |
|
|
// | PHP Version 4 | |
5 |
|
|
// +----------------------------------------------------------------------+ |
6 |
|
|
// | Copyright (c) 1997-2003 The PHP Group | |
7 |
|
|
// +----------------------------------------------------------------------+ |
8 |
|
|
// | This source file is subject to version 2.02 of the PHP license, | |
9 |
|
|
// | that is bundled with this package in the file LICENSE, and is | |
10 |
|
|
// | available at through the world-wide-web at | |
11 |
|
|
// | http://www.php.net/license/2_02.txt. | |
12 |
|
|
// | If you did not receive a copy of the PHP license and are unable to | |
13 |
|
|
// | obtain it through the world-wide-web, please send a note to | |
14 |
|
|
// | license@php.net so we can mail you a copy immediately. | |
15 |
|
|
// +----------------------------------------------------------------------+ |
16 |
|
|
// | Authors: | |
17 |
|
|
// +----------------------------------------------------------------------+ |
18 |
|
|
// |
19 |
joko |
1.2 |
// $Id: DBnested.php,v 1.16 2003/03/04 18:57:18 cain Exp $ |
20 |
joko |
1.1 |
|
21 |
|
|
require_once('Tree/Common.php'); |
22 |
|
|
require_once('Tree/Error.php'); |
23 |
|
|
|
24 |
|
|
/** |
25 |
|
|
* this class implements methods to work on a tree saved using the nested |
26 |
|
|
* tree model |
27 |
|
|
* explaination: http://research.calacademy.org/taf/proceedings/ballew/index.htm |
28 |
|
|
* |
29 |
|
|
* @access public |
30 |
|
|
* @package Tree |
31 |
|
|
*/ |
32 |
|
|
class Tree_Dynamic_DBnested extends Tree_Common |
33 |
|
|
// FIXXME should actually extend Tree_Common, to use the methods provided in there... but we need to connect |
34 |
|
|
// to the db here, so we extend optionsDB for now, may be use "aggregate" function to fix that |
35 |
|
|
{ |
36 |
|
|
|
37 |
|
|
var $debug = 0; |
38 |
|
|
|
39 |
|
|
var $options = array( |
40 |
|
|
// FIXXME to be implemented |
41 |
|
|
'whereAddOn'=>'' // add on for the where clause, this string is simply added behind the WHERE in the select |
42 |
|
|
// so you better make sure its correct SQL :-), i.e. 'uid=3' |
43 |
|
|
// this is needed i.e. when you are saving many trees in one db-table |
44 |
|
|
,'table' =>'' // |
45 |
|
|
// since the internal names are fixed, to be portable between different |
46 |
|
|
// DB tables with different column namings, we map the internal name to the real column name |
47 |
|
|
// using this array here, if it stays empty the internal names are used, which are: |
48 |
|
|
// id, left, right |
49 |
|
|
,'columnNameMaps'=>array( |
50 |
|
|
//'id' => 'node_id', // use "node_id" as "id" |
51 |
|
|
'left' => 'l' // since mysql at least doesnt support 'left' ... |
52 |
|
|
,'right' => 'r' // ...as a column name we set default to the first letter only |
53 |
|
|
//'name' => 'nodeName' // |
54 |
|
|
,'parentId' => 'parent' // parent id |
55 |
|
|
) |
56 |
|
|
,'order' => '' // needed for sorting the tree, currently only used in Memory_DBnested |
57 |
|
|
); |
58 |
|
|
|
59 |
|
|
// the defined methods here are proposals for the implementation, |
60 |
|
|
// they are named the same, as the methods in the "Memory" branch, if possible |
61 |
|
|
// it would be cool to keep the same naming and if the same parameters would be possible too |
62 |
|
|
// then it would be even better, so one could easily change from any kind of |
63 |
|
|
// tree-implementation to another, without changing the source code, only the setupXXX would need to be changed |
64 |
|
|
|
65 |
|
|
/** |
66 |
|
|
* |
67 |
|
|
* |
68 |
|
|
* @access public |
69 |
|
|
* @version 2002/03/02 |
70 |
|
|
* @author Wolfram Kriesing <wolfram@kriesing.de> |
71 |
|
|
* @param |
72 |
|
|
* @return |
73 |
|
|
*/ |
74 |
|
|
function __construct( $dsn , $options=array() ) |
75 |
|
|
{ |
76 |
|
|
Tree_Dynamic_DBnested( $dsn , $options ); |
77 |
|
|
} |
78 |
|
|
|
79 |
|
|
/** |
80 |
|
|
* |
81 |
|
|
* |
82 |
|
|
* @access public |
83 |
|
|
* @version 2002/03/02 |
84 |
|
|
* @author Wolfram Kriesing <wolfram@kriesing.de> |
85 |
|
|
* @param |
86 |
|
|
* @return |
87 |
|
|
*/ |
88 |
|
|
function Tree_Dynamic_DBnested( $dsn , $options=array() ) |
89 |
|
|
{ |
90 |
|
|
parent::Tree_OptionsDB( $dsn , $options ); // instanciate DB |
91 |
|
|
$this->table = $this->getOption('table'); |
92 |
|
|
} |
93 |
|
|
|
94 |
|
|
/** |
95 |
|
|
* add a new element to the tree |
96 |
|
|
* there are three ways to use this method |
97 |
|
|
* 1. |
98 |
|
|
* give only the $parentId and the $newValues will be inserted as the first child of this parent |
99 |
|
|
* i.e. // insert a new element under the parent with the ID=7 |
100 |
|
|
* $tree->add( array('name'=>'new element name') , 7 ); |
101 |
|
|
* 2. |
102 |
|
|
* give the $prevId ($parentId will be dismissed) and the new element |
103 |
|
|
* will be inserted in the tree after the element with the ID=$prevId |
104 |
|
|
* the parentId is not necessary because the prevId defines exactly where |
105 |
|
|
* the new element has to be place in the tree, and the parent is the same as |
106 |
|
|
* for the element with the ID=$prevId |
107 |
|
|
* i.e. // insert a new element after the element with the ID=5 |
108 |
|
|
* $tree->add( array('name'=>'new') , 0 , 5 ); |
109 |
|
|
* 3. |
110 |
|
|
* neither $parentId nor prevId is given, then the root element will be inserted |
111 |
|
|
* this requires that programmer is responsible to confirm this |
112 |
|
|
* this method does not (yet) check if there is already a root element saved !!! |
113 |
|
|
* |
114 |
|
|
* @access public |
115 |
|
|
* @author Wolfram Kriesing <wolfram@kriesing.de> |
116 |
|
|
* @param array $newValues this array contains the values that shall be inserted in the db-table |
117 |
|
|
* @param integer $parentId the id of the element which shall be the parent of the new element |
118 |
|
|
* @param integer $prevId the id of the element which shall preceed the one to be inserted |
119 |
|
|
* use either 'parentId' or 'prevId' |
120 |
|
|
* @return integer the ID of the element that had been inserted |
121 |
|
|
*/ |
122 |
|
|
function add( $newValues , $parentId=0 , $prevId=0 ) |
123 |
|
|
{ |
124 |
|
|
$lName = $this->_getColName('left'); |
125 |
|
|
$rName = $this->_getColName('right'); |
126 |
|
|
$prevVisited = 0; |
127 |
|
|
|
128 |
|
|
// check the DB-table if the columns which are given as keys |
129 |
|
|
// in the array $newValues do really exist, if not remove them from the array |
130 |
|
|
// FIXXME do the above described |
131 |
|
|
|
132 |
|
|
if( $parentId || $prevId ) // if no parent and no prevId is given the root shall be added |
133 |
|
|
{ |
134 |
|
|
if( $prevId ) |
135 |
|
|
{ |
136 |
|
|
$element = $this->getElement( $prevId ); |
137 |
|
|
$parentId = $element['parentId']; // we also need the parent id of the element, to write it in the db |
138 |
|
|
} |
139 |
|
|
else |
140 |
|
|
{ |
141 |
|
|
$element = $this->getElement( $parentId ); |
142 |
|
|
} |
143 |
|
|
$newValues['parentId'] = $parentId; |
144 |
|
|
|
145 |
|
|
if( PEAR::isError($element) ) |
146 |
|
|
return $element; |
147 |
|
|
|
148 |
|
|
// get the "visited"-value where to add the new element behind |
149 |
|
|
// if $prevId is given, we need to use the right-value |
150 |
|
|
// if only the $parentId is given we need to use the left-value |
151 |
|
|
// look at it graphically, that made me understand it :-) |
152 |
|
|
// i.e. at: http://research.calacademy.org/taf/proceedings/ballew/sld034.htm |
153 |
|
|
$prevVisited = $prevId ? $element['right'] : $element['left']; |
154 |
|
|
|
155 |
|
|
// FIXXME start transaction here |
156 |
|
|
|
157 |
|
|
if( PEAR::isError($err=$this->_add( $prevVisited , 1 )) ) |
158 |
|
|
{ |
159 |
|
|
// FIXXME rollback |
160 |
|
|
//$this->dbh->rollback(); |
161 |
|
|
return $err; |
162 |
|
|
} |
163 |
|
|
} |
164 |
|
|
|
165 |
|
|
// inserting _one_ new element in the tree |
166 |
|
|
$newData = array(); |
167 |
|
|
foreach( $newValues as $key=>$value ) // quote the values, as needed for the insert |
168 |
|
|
{ |
169 |
|
|
$newData[$this->_getColName($key)] = $this->dbh->quote($value); |
170 |
|
|
} |
171 |
|
|
|
172 |
|
|
// set the proper right and left values |
173 |
|
|
$newData[$lName] = $prevVisited+1; |
174 |
|
|
$newData[$rName] = $prevVisited+2; |
175 |
|
|
|
176 |
|
|
// use sequences to create a new id in the db-table |
177 |
|
|
$nextId = $this->dbh->nextId($this->table); |
178 |
|
|
$query = sprintf( 'INSERT INTO %s (%s,%s) VALUES (%s,%s)', |
179 |
|
|
$this->table , |
180 |
|
|
$this->_getColName('id'), |
181 |
|
|
implode( "," , array_keys($newData) ) , |
182 |
|
|
$nextId, |
183 |
|
|
implode( "," , $newData ) |
184 |
|
|
); |
185 |
|
|
if( DB::isError( $res = $this->dbh->query($query) ) ) |
186 |
|
|
{ |
187 |
|
|
// rollback |
188 |
|
|
return $this->_throwError( $res->getMessage() , __LINE__ ); |
189 |
|
|
} |
190 |
|
|
// commit here |
191 |
|
|
|
192 |
|
|
return $nextId; |
193 |
|
|
} // end of function |
194 |
|
|
|
195 |
|
|
/** |
196 |
|
|
* this method only updates the left/right values of all the |
197 |
|
|
* elements that are affected by the insertion |
198 |
|
|
* be sure to set the parentId of the element(s) you insert |
199 |
|
|
* |
200 |
|
|
* @param int this parameter is not the ID!!! |
201 |
|
|
* it is the previous visit number, that means |
202 |
|
|
* if you are inserting a child, you need to use the left-value |
203 |
|
|
* of the parent |
204 |
|
|
* if you are inserting a "next" element, on the same level |
205 |
|
|
* you need to give the right value !! |
206 |
|
|
* @param int the number of elements you plan to insert |
207 |
|
|
* @return mixed either true on success or a Tree_Error on failure |
208 |
|
|
*/ |
209 |
|
|
function _add( $prevVisited , $numberOfElements=1 ) |
210 |
|
|
{ |
211 |
|
|
$lName = $this->_getColName('left'); |
212 |
|
|
$rName = $this->_getColName('right'); |
213 |
|
|
|
214 |
|
|
// update the elements which will be affected by the new insert |
215 |
|
|
$query = sprintf( 'UPDATE %s SET %s=%s+%s WHERE%s %s>%s', |
216 |
|
|
$this->table, |
217 |
|
|
$lName,$lName, |
218 |
|
|
$numberOfElements*2, |
219 |
|
|
$this->_getWhereAddOn(), |
220 |
|
|
$lName, |
221 |
|
|
$prevVisited ); |
222 |
|
|
if( DB::isError( $res = $this->dbh->query($query) ) ) |
223 |
|
|
{ |
224 |
|
|
// FIXXME rollback |
225 |
|
|
return $this->_throwError( $res->getMessage() , __LINE__ ); |
226 |
|
|
} |
227 |
|
|
|
228 |
|
|
$query = sprintf( 'UPDATE %s SET %s=%s+%s WHERE%s %s>%s', |
229 |
|
|
$this->table, |
230 |
|
|
$rName,$rName, |
231 |
|
|
$numberOfElements*2, |
232 |
|
|
$this->_getWhereAddOn(), |
233 |
|
|
$rName, |
234 |
|
|
$prevVisited ); |
235 |
|
|
if( DB::isError( $res = $this->dbh->query($query) ) ) |
236 |
|
|
{ |
237 |
|
|
// FIXXME rollback |
238 |
|
|
return $this->_throwError( $res->getMessage() , __LINE__ ); |
239 |
|
|
} |
240 |
|
|
return true; |
241 |
|
|
} |
242 |
|
|
|
243 |
|
|
/** |
244 |
|
|
* remove a tree element |
245 |
|
|
* this automatically remove all children and their children |
246 |
|
|
* if a node shall be removed that has children |
247 |
|
|
* |
248 |
|
|
* @access public |
249 |
|
|
* @author Wolfram Kriesing <wolfram@kriesing.de> |
250 |
|
|
* @param integer $id the id of the element to be removed |
251 |
|
|
* @return boolean returns either true or throws an error |
252 |
|
|
*/ |
253 |
|
|
function remove( $id ) |
254 |
|
|
{ |
255 |
|
|
$element = $this->getElement( $id ); |
256 |
|
|
if( PEAR::isError($element) ) |
257 |
|
|
return $element; |
258 |
|
|
|
259 |
|
|
// FIXXME start transaction |
260 |
|
|
//$this->dbh->autoCommit(false); |
261 |
|
|
$query = sprintf( 'DELETE FROM %s WHERE%s %s BETWEEN %s AND %s', |
262 |
|
|
$this->table, |
263 |
|
|
$this->_getWhereAddOn(), |
264 |
|
|
$this->_getColName('left'), |
265 |
|
|
$element['left'],$element['right']); |
266 |
|
|
if( DB::isError( $res = $this->dbh->query($query) ) ) |
267 |
|
|
{ |
268 |
|
|
// FIXXME rollback |
269 |
|
|
//$this->dbh->rollback(); |
270 |
|
|
return $this->_throwError( $res->getMessage() , __LINE__ ); |
271 |
|
|
} |
272 |
|
|
|
273 |
|
|
if( PEAR::isError($err=$this->_remove( $element )) ) |
274 |
|
|
{ |
275 |
|
|
// FIXXME rollback |
276 |
|
|
//$this->dbh->rollback(); |
277 |
|
|
return $err; |
278 |
|
|
} |
279 |
|
|
return true; |
280 |
|
|
} |
281 |
|
|
|
282 |
|
|
/** |
283 |
|
|
* removes a tree element, but only updates the left/right values |
284 |
|
|
* to make it seem as if the given element would not exist anymore |
285 |
|
|
* it doesnt remove the row(s) in the db itself! |
286 |
|
|
* |
287 |
|
|
* @see getElement() |
288 |
|
|
* @access private |
289 |
|
|
* @author Wolfram Kriesing <wolfram@kriesing.de> |
290 |
|
|
* @param array the entire element returned by "getElement" |
291 |
|
|
* @return boolean returns either true or throws an error |
292 |
|
|
*/ |
293 |
|
|
function _remove( $element ) |
294 |
|
|
{ |
295 |
|
|
$delta = $element['right'] - $element['left'] +1; |
296 |
|
|
$lName = $this->_getColName('left'); |
297 |
|
|
$rName = $this->_getColName('right'); |
298 |
|
|
|
299 |
|
|
// update the elements which will be affected by the remove |
300 |
|
|
$query = sprintf( "UPDATE %s SET %s=%s-$delta, %s=%s-$delta WHERE%s %s>%s", |
301 |
|
|
$this->table, |
302 |
|
|
$lName,$lName, |
303 |
|
|
$rName,$rName, |
304 |
|
|
$this->_getWhereAddOn(), |
305 |
|
|
$lName,$element['left'] ); |
306 |
|
|
if( DB::isError( $res = $this->dbh->query($query) ) ) |
307 |
|
|
{ |
308 |
|
|
// the rollback shall be done by the method calling this one, since it is only private we can do that |
309 |
|
|
return $this->_throwError( $res->getMessage() , __LINE__ ); |
310 |
|
|
} |
311 |
|
|
|
312 |
|
|
$query = sprintf( "UPDATE %s SET %s=%s-$delta WHERE%s %s<%s AND %s>%s", |
313 |
|
|
$this->table, |
314 |
|
|
$rName,$rName, |
315 |
|
|
$this->_getWhereAddOn(), |
316 |
|
|
$lName,$element['left'], |
317 |
|
|
$rName,$element['right'] ); |
318 |
|
|
if( DB::isError( $res = $this->dbh->query($query) ) ) |
319 |
|
|
{ |
320 |
|
|
// the rollback shall be done by the method calling this one, since it is only private |
321 |
|
|
return $this->_throwError( $res->getMessage() , __LINE__ ); |
322 |
|
|
} |
323 |
|
|
// FIXXME commit - should that not also be done in the method calling this one? like when an error occurs? |
324 |
|
|
//$this->dbh->commit(); |
325 |
|
|
return true; |
326 |
|
|
} // end of function |
327 |
|
|
|
328 |
|
|
/** |
329 |
|
|
* move an entry under a given parent or behind a given entry. |
330 |
|
|
* If a newPrevId is given the newParentId is dismissed! |
331 |
|
|
* call it either like this: |
332 |
|
|
* $tree->move( x , y ) |
333 |
|
|
* to move the element (or entire tree) with the id x |
334 |
|
|
* under the element with the id y |
335 |
|
|
* or |
336 |
|
|
* $tree->move( x , 0 , y ); // ommit the second parameter by setting it to 0 |
337 |
|
|
* to move the element (or entire tree) with the id x |
338 |
|
|
* behind the element with the id y |
339 |
|
|
* or |
340 |
|
|
* $tree->move( array(x1,x2,x3) , ... |
341 |
|
|
* the first parameter can also be an array of elements that shall be moved |
342 |
|
|
* the second and third para can be as described above |
343 |
|
|
* If you are using the Memory_DBnested then this method would be invain, |
344 |
|
|
* since Memory.php already does the looping through multiple elements, but if |
345 |
|
|
* Dynamic_DBnested is used we need to do the looping here |
346 |
|
|
* |
347 |
|
|
* @version 2002/06/08 |
348 |
|
|
* @access public |
349 |
|
|
* @author Wolfram Kriesing <wolfram@kriesing.de> |
350 |
|
|
* @param integer the id(s) of the element(s) that shall be moved |
351 |
|
|
* @param integer the id of the element which will be the new parent |
352 |
|
|
* @param integer if prevId is given the element with the id idToMove |
353 |
|
|
* shall be moved _behind_ the element with id=prevId |
354 |
|
|
* if it is 0 it will be put at the beginning |
355 |
|
|
* @return mixed true for success, Tree_Error on failure |
356 |
|
|
*/ |
357 |
|
|
function move( $idsToMove , $newParentId , $newPrevId=0 ) |
358 |
|
|
{ |
359 |
|
|
settype($idsToMove,'array'); |
360 |
|
|
$errors = array(); |
361 |
|
|
foreach( $idsToMove as $idToMove ) |
362 |
|
|
{ |
363 |
|
|
$ret = $this->_move( $idToMove , $newParentId , $newPrevId ); |
364 |
|
|
if( PEAR::isError($ret) ) |
365 |
|
|
$errors[] = $ret; |
366 |
|
|
} |
367 |
|
|
// FIXXME the error in a nicer way, or even better let the throwError method do it!!! |
368 |
|
|
if( sizeof($errors) ) |
369 |
|
|
{ |
370 |
|
|
return $this->_throwError(serialize($errors),__LINE__); |
371 |
|
|
} |
372 |
|
|
return true; |
373 |
|
|
} |
374 |
|
|
|
375 |
|
|
/** |
376 |
|
|
* this method moves one tree element |
377 |
|
|
* |
378 |
|
|
* @see move() |
379 |
|
|
* @version 2002/04/29 |
380 |
|
|
* @access public |
381 |
|
|
* @author Wolfram Kriesing <wolfram@kriesing.de> |
382 |
|
|
* @param integer the id of the element that shall be moved |
383 |
|
|
* @param integer the id of the element which will be the new parent |
384 |
|
|
* @param integer if prevId is given the element with the id idToMove |
385 |
|
|
* shall be moved _behind_ the element with id=prevId |
386 |
|
|
* if it is 0 it will be put at the beginning |
387 |
|
|
* @return mixed true for success, Tree_Error on failure |
388 |
|
|
*/ |
389 |
|
|
function _move( $idToMove , $newParentId , $newPrevId=0 ) |
390 |
|
|
{ |
391 |
|
|
// do some integrity checks first |
392 |
joko |
1.2 |
if ($newPrevId) { |
393 |
|
|
if ($newPrevId==$idToMove) { // dont let people move an element behind itself, tell it succeeded, since it already is there :-) |
394 |
joko |
1.1 |
return true; |
395 |
|
|
} |
396 |
joko |
1.2 |
if (PEAR::isError($newPrevious=$this->getElement($newPrevId))) { |
397 |
joko |
1.1 |
return $newPrevious; |
398 |
joko |
1.2 |
} |
399 |
joko |
1.1 |
$newParentId = $newPrevious['parentId']; |
400 |
joko |
1.2 |
} else { |
401 |
|
|
if ($newParentId==0) { |
402 |
joko |
1.1 |
return $this->_throwError( 'no parent id given' , __LINE__ ); |
403 |
|
|
} |
404 |
joko |
1.2 |
if ($this->isChildOf($idToMove,$newParentId)) { // if the element shall be moved under one of its children, return false |
405 |
joko |
1.1 |
return $this->_throwError( 'can not move an element under one of its children' , __LINE__ ); |
406 |
|
|
} |
407 |
joko |
1.2 |
if ($newParentId==$idToMove) { // dont do anything to let an element be moved under itself, which is bullshit |
408 |
joko |
1.1 |
return true; |
409 |
|
|
} |
410 |
joko |
1.2 |
if (PEAR::isError($newParent=$this->getElement($newParentId))) { // try to retreive the data of the parent element |
411 |
joko |
1.1 |
return $newParent; |
412 |
|
|
} |
413 |
|
|
} |
414 |
|
|
|
415 |
joko |
1.2 |
if (PEAR::isError($element=$this->getElement($idToMove))) { // get the data of the element itself |
416 |
joko |
1.1 |
return $element; |
417 |
|
|
} |
418 |
|
|
|
419 |
|
|
$numberOfElements = ($element['right'] - $element['left']+1)/2; |
420 |
|
|
$prevVisited = $newPrevId ? $newPrevious['right'] : $newParent['left']; |
421 |
|
|
|
422 |
|
|
// FIXXME start transaction |
423 |
|
|
|
424 |
|
|
// add the left/right values in the new parent, to have the space to move the new values in |
425 |
joko |
1.2 |
if (PEAR::isError($err=$this->_add( $prevVisited , $numberOfElements ))) { |
426 |
joko |
1.1 |
// FIXXME rollback |
427 |
|
|
//$this->dbh->rollback(); |
428 |
|
|
return $err; |
429 |
|
|
} |
430 |
|
|
|
431 |
|
|
// update the parentId of the element with $idToMove |
432 |
joko |
1.2 |
if (PEAR::isError($err=$this->update($idToMove,array('parentId'=>$newParentId)))) { |
433 |
joko |
1.1 |
// FIXXME rollback |
434 |
|
|
//$this->dbh->rollback(); |
435 |
|
|
return $err; |
436 |
|
|
} |
437 |
|
|
|
438 |
|
|
// update the lefts and rights of those elements that shall be moved |
439 |
|
|
|
440 |
|
|
// first get the offset we need to add to the left/right values |
441 |
|
|
// if $newPrevId is given we need to get the right value, otherwise the left |
442 |
|
|
// since the left/right has changed, because we already updated it up there we need to |
443 |
|
|
// get them again, we have to do that anyway, to have the proper new left/right values |
444 |
joko |
1.2 |
if ($newPrevId) { |
445 |
|
|
if (PEAR::isError($temp = $this->getElement( $newPrevId ))) { |
446 |
joko |
1.1 |
// FIXXME rollback |
447 |
|
|
//$this->dbh->rollback(); |
448 |
|
|
return $temp; |
449 |
|
|
} |
450 |
|
|
$calcWith = $temp['right']; |
451 |
joko |
1.2 |
} else { |
452 |
|
|
if (PEAR::isError($temp=$this->getElement($newParentId))) { |
453 |
joko |
1.1 |
// FIXXME rollback |
454 |
|
|
//$this->dbh->rollback(); |
455 |
|
|
return $temp; |
456 |
|
|
} |
457 |
|
|
$calcWith = $temp['left']; |
458 |
|
|
} |
459 |
|
|
|
460 |
|
|
// get the element that shall be moved again, since the left and right might have changed by the add-call |
461 |
joko |
1.2 |
if (PEAR::isError($element=$this->getElement($idToMove))) { |
462 |
joko |
1.1 |
return $element; |
463 |
|
|
} |
464 |
|
|
|
465 |
|
|
$offset = $calcWith - $element['left']; // calc the offset that the element to move has to the spot where it should go |
466 |
|
|
$offset++; // correct the offset by one, since it needs to go inbetween! |
467 |
|
|
|
468 |
|
|
$lName = $this->_getColName('left'); |
469 |
|
|
$rName = $this->_getColName('right'); |
470 |
|
|
$query = sprintf( "UPDATE %s SET %s=%s+$offset,%s=%s+$offset WHERE%s %s>%s AND %s<%s", |
471 |
|
|
$this->table, |
472 |
|
|
$rName,$rName, |
473 |
|
|
$lName,$lName, |
474 |
|
|
$this->_getWhereAddOn(), |
475 |
|
|
$lName,$element['left']-1, |
476 |
|
|
$rName,$element['right']+1 ); |
477 |
joko |
1.2 |
if (DB::isError($res=$this->dbh->query($query))) { |
478 |
joko |
1.1 |
// FIXXME rollback |
479 |
|
|
//$this->dbh->rollback(); |
480 |
|
|
return $this->_throwError( $res->getMessage() , __LINE__ ); |
481 |
|
|
} |
482 |
|
|
|
483 |
|
|
// remove the part of the tree where the element(s) was/were before |
484 |
joko |
1.2 |
if (PEAR::isError($err=$this->_remove($element))) { |
485 |
joko |
1.1 |
// FIXXME rollback |
486 |
|
|
//$this->dbh->rollback(); |
487 |
|
|
return $err; |
488 |
|
|
} |
489 |
|
|
// FIXXME commit all changes |
490 |
|
|
//$this->dbh->commit(); |
491 |
|
|
|
492 |
|
|
return true; |
493 |
|
|
} // end of function |
494 |
|
|
|
495 |
|
|
/** |
496 |
|
|
* update the tree element given by $id with the values in $newValues |
497 |
|
|
* |
498 |
|
|
* @access public |
499 |
|
|
* @author Wolfram Kriesing <wolfram@kriesing.de> |
500 |
|
|
* @param int the id of the element to update |
501 |
|
|
* @param array the new values, the index is the col name |
502 |
|
|
* @return mixed either true or an Tree_Error |
503 |
|
|
*/ |
504 |
joko |
1.2 |
function update($id,$newValues) |
505 |
joko |
1.1 |
{ |
506 |
|
|
// jsut to be sure nothing gets screwed up :-) |
507 |
joko |
1.2 |
unset($newValues[$this->_getColName('left')]); |
508 |
|
|
unset($newValues[$this->_getColName('right')]); |
509 |
|
|
unset($newValues[$this->_getColName('parentId')]); |
510 |
joko |
1.1 |
|
511 |
|
|
// updating _one_ element in the tree |
512 |
|
|
$values = array(); |
513 |
joko |
1.2 |
foreach ($newValues as $key=>$value) { |
514 |
joko |
1.1 |
$values[] = $this->_getColName($key).'='.$this->dbh->quote($value); |
515 |
joko |
1.2 |
} |
516 |
joko |
1.1 |
$query = sprintf( 'UPDATE %s SET %s WHERE%s %s=%s', |
517 |
|
|
$this->table, |
518 |
|
|
implode(',',$values), |
519 |
|
|
$this->_getWhereAddOn(), |
520 |
|
|
$this->_getColName('id'), |
521 |
|
|
$id); |
522 |
joko |
1.2 |
if (DB::isError( $res=$this->dbh->query($query))) { |
523 |
joko |
1.1 |
// FIXXME raise PEAR error |
524 |
|
|
return $this->_throwError( $res->getMessage() , __LINE__ ); |
525 |
|
|
} |
526 |
|
|
|
527 |
|
|
return true; |
528 |
|
|
} // end of function |
529 |
|
|
|
530 |
|
|
/** |
531 |
|
|
* copy a subtree/node/... under a new parent or/and behind a given element |
532 |
|
|
* |
533 |
|
|
* |
534 |
|
|
* @access public |
535 |
|
|
* @author Wolfram Kriesing <wolfram@kriesing.de> |
536 |
|
|
* @param |
537 |
|
|
* @return |
538 |
|
|
*/ |
539 |
|
|
function copy( $id , $parentId=0 , $prevId=0 ) |
540 |
|
|
{ |
541 |
|
|
return $this->_throwError( 'copy-method is not implemented yet!' , __LINE__ ); |
542 |
|
|
// get element tree |
543 |
|
|
// $this->addTree |
544 |
|
|
} // end of function |
545 |
|
|
|
546 |
|
|
|
547 |
|
|
/** |
548 |
|
|
* get the root |
549 |
|
|
* |
550 |
|
|
* @access public |
551 |
|
|
* @version 2002/03/02 |
552 |
|
|
* @author Wolfram Kriesing <wolfram@kriesing.de> |
553 |
|
|
* @param |
554 |
|
|
* @return mixed either the data of the root element or an Tree_Error |
555 |
|
|
*/ |
556 |
|
|
function getRoot() |
557 |
|
|
{ |
558 |
|
|
$query = sprintf( 'SELECT * FROM %s WHERE%s %s=1', |
559 |
|
|
$this->table, |
560 |
|
|
$this->_getWhereAddOn(), |
561 |
|
|
$this->_getColName('left')); |
562 |
|
|
if( DB::isError( $res = $this->dbh->getRow($query) ) ) |
563 |
|
|
{ |
564 |
|
|
return $this->_throwError( $res->getMessage() , __LINE__ ); |
565 |
|
|
} |
566 |
|
|
return $this->_prepareResult( $res ); |
567 |
|
|
} // end of function |
568 |
|
|
|
569 |
|
|
/** |
570 |
|
|
* |
571 |
|
|
* |
572 |
|
|
* @access public |
573 |
|
|
* @version 2002/03/02 |
574 |
|
|
* @author Wolfram Kriesing <wolfram@kriesing.de> |
575 |
|
|
* @param |
576 |
|
|
* @return mixed either the data of the requested element or an Tree_Error |
577 |
|
|
*/ |
578 |
|
|
function getElement( $id ) |
579 |
|
|
{ |
580 |
|
|
$query = sprintf( 'SELECT * FROM %s WHERE%s %s=%s', |
581 |
|
|
$this->table, |
582 |
|
|
$this->_getWhereAddOn(), |
583 |
|
|
$this->_getColName('id'), |
584 |
|
|
$id); |
585 |
|
|
if( DB::isError( $res = $this->dbh->getRow($query) ) ) |
586 |
|
|
{ |
587 |
|
|
return $this->_throwError( $res->getMessage() , __LINE__ ); |
588 |
|
|
} |
589 |
|
|
if( !$res ) |
590 |
|
|
return $this->_throwError( "Element with id $id does not exist!" , __LINE__ ); |
591 |
|
|
|
592 |
|
|
return $this->_prepareResult( $res ); |
593 |
|
|
} // end of function |
594 |
|
|
|
595 |
|
|
/** |
596 |
|
|
* |
597 |
|
|
* |
598 |
|
|
* @access public |
599 |
|
|
* @version 2002/03/02 |
600 |
|
|
* @author Wolfram Kriesing <wolfram@kriesing.de> |
601 |
|
|
* @param |
602 |
|
|
* @return mixed either the data of the requested element or an Tree_Error |
603 |
|
|
*/ |
604 |
joko |
1.2 |
function getChild($id) |
605 |
joko |
1.1 |
{ |
606 |
|
|
// subqueries would be cool :-) |
607 |
|
|
$curElement = $this->getElement( $id ); |
608 |
joko |
1.2 |
if (PEAR::isError($curElement)) { |
609 |
joko |
1.1 |
return $curElement; |
610 |
joko |
1.2 |
} |
611 |
joko |
1.1 |
|
612 |
|
|
$query = sprintf( 'SELECT * FROM %s WHERE%s %s=%s', |
613 |
|
|
$this->table, |
614 |
|
|
$this->_getWhereAddOn(), |
615 |
|
|
$this->_getColName('left'), |
616 |
|
|
$curElement['left']+1 ); |
617 |
joko |
1.2 |
if (DB::isError( $res = $this->dbh->getRow($query))) { |
618 |
joko |
1.1 |
return $this->_throwError( $res->getMessage() , __LINE__ ); |
619 |
|
|
} |
620 |
|
|
return $this->_prepareResult( $res ); |
621 |
|
|
} |
622 |
|
|
|
623 |
|
|
/** |
624 |
|
|
* gets the path from the element with the given id down |
625 |
|
|
* to the root |
626 |
|
|
* the returned array is sorted to start at root |
627 |
|
|
* for simply walking through and retreiving the path |
628 |
|
|
* |
629 |
|
|
* @access public |
630 |
|
|
* @version 2002/03/02 |
631 |
|
|
* @author Wolfram Kriesing <wolfram@kriesing.de> |
632 |
|
|
* @param |
633 |
|
|
* @return mixed either the data of the requested elements or an Tree_Error |
634 |
|
|
*/ |
635 |
|
|
function getPath( $id ) |
636 |
|
|
{ |
637 |
|
|
// subqueries would be cool :-) |
638 |
|
|
$curElement = $this->getElement( $id ); |
639 |
|
|
|
640 |
|
|
$query = sprintf( 'SELECT * FROM %s WHERE%s %s<=%s AND %s>=%s ORDER BY %s', |
641 |
|
|
$this->table, |
642 |
|
|
$this->_getWhereAddOn(), |
643 |
|
|
$this->_getColName('left'), |
644 |
|
|
$curElement['left'], |
645 |
|
|
$this->_getColName('right'), |
646 |
|
|
$curElement['right'], |
647 |
|
|
$this->_getColName('left') ); |
648 |
joko |
1.2 |
if (DB::isError( $res = $this->dbh->getAll($query))) { |
649 |
joko |
1.1 |
return $this->_throwError( $res->getMessage() , __LINE__ ); |
650 |
|
|
} |
651 |
|
|
return $this->_prepareResults( $res ); |
652 |
|
|
} |
653 |
|
|
|
654 |
|
|
/** |
655 |
|
|
* gets the element to the left, the left visit |
656 |
|
|
* |
657 |
|
|
* @access public |
658 |
|
|
* @version 2002/03/07 |
659 |
|
|
* @author Wolfram Kriesing <wolfram@kriesing.de> |
660 |
|
|
* @param |
661 |
|
|
* @return mixed either the data of the requested element or an Tree_Error |
662 |
|
|
*/ |
663 |
|
|
function getLeft( $id ) |
664 |
|
|
{ |
665 |
|
|
$element = $this->getElement( $id ); |
666 |
|
|
if( PEAR::isError($element) ) |
667 |
|
|
return $element; |
668 |
|
|
|
669 |
|
|
$query = sprintf( 'SELECT * FROM %s WHERE%s (%s=%s OR %s=%s)', |
670 |
|
|
$this->table, |
671 |
|
|
$this->_getWhereAddOn(), |
672 |
|
|
$this->_getColName('right'),$element['left']-1, |
673 |
|
|
$this->_getColName('left'),$element['left']-1 ); |
674 |
|
|
if( DB::isError( $res = $this->dbh->getRow($query) ) ) |
675 |
|
|
{ |
676 |
|
|
return $this->_throwError( $res->getMessage() , __LINE__ ); |
677 |
|
|
} |
678 |
|
|
return $this->_prepareResult( $res ); |
679 |
|
|
} |
680 |
|
|
|
681 |
|
|
/** |
682 |
|
|
* gets the element to the right, the right visit |
683 |
|
|
* |
684 |
|
|
* @access public |
685 |
|
|
* @version 2002/03/07 |
686 |
|
|
* @author Wolfram Kriesing <wolfram@kriesing.de> |
687 |
|
|
* @param |
688 |
|
|
* @return mixed either the data of the requested element or an Tree_Error |
689 |
|
|
*/ |
690 |
|
|
function getRight( $id ) |
691 |
|
|
{ |
692 |
|
|
$element = $this->getElement( $id ); |
693 |
|
|
if( PEAR::isError($element) ) |
694 |
|
|
return $element; |
695 |
|
|
|
696 |
|
|
$query = sprintf( 'SELECT * FROM %s WHERE%s (%s=%s OR %s=%s)', |
697 |
|
|
$this->table, |
698 |
|
|
$this->_getWhereAddOn(), |
699 |
|
|
$this->_getColName('left'),$element['right']+1, |
700 |
|
|
$this->_getColName('right'),$element['right']+1); |
701 |
|
|
if( DB::isError( $res = $this->dbh->getRow($query) ) ) |
702 |
|
|
{ |
703 |
|
|
return $this->_throwError( $res->getMessage() , __LINE__ ); |
704 |
|
|
} |
705 |
|
|
return $this->_prepareResult( $res ); |
706 |
|
|
} |
707 |
|
|
|
708 |
|
|
/** |
709 |
|
|
* get the parent of the element with the given id |
710 |
|
|
* |
711 |
|
|
* @access public |
712 |
|
|
* @version 2002/04/15 |
713 |
|
|
* @author Wolfram Kriesing <wolfram@kriesing.de> |
714 |
|
|
* @param |
715 |
|
|
* @return mixed the array with the data of the parent element |
716 |
|
|
* or false, if there is no parent, if the element is the root |
717 |
|
|
* or an Tree_Error |
718 |
|
|
*/ |
719 |
|
|
function getParent( $id ) |
720 |
|
|
{ |
721 |
|
|
$query = sprintf( 'SELECT p.* FROM %s p,%s e WHERE%s e.%s=p.%s AND e.%s=%s', |
722 |
|
|
$this->table,$this->table, |
723 |
|
|
$this->_getWhereAddOn( ' AND ' , 'p' ), |
724 |
|
|
$this->_getColName('parentId'), |
725 |
|
|
$this->_getColName('id'), |
726 |
|
|
$this->_getColName('id'), |
727 |
|
|
$id); |
728 |
|
|
if( DB::isError( $res = $this->dbh->getRow($query) ) ) |
729 |
|
|
{ |
730 |
|
|
return $this->_throwError( $res->getMessage() , __LINE__ ); |
731 |
|
|
} |
732 |
|
|
return $this->_prepareResult( $res ); |
733 |
|
|
} |
734 |
|
|
|
735 |
|
|
/** |
736 |
|
|
* get the children of the given element |
737 |
|
|
* or if the parameter is an array, it gets the children of all |
738 |
|
|
* the elements given by their ids in the array |
739 |
|
|
* |
740 |
|
|
* @access public |
741 |
|
|
* @version 2002/04/15 |
742 |
|
|
* @author Wolfram Kriesing <wolfram@kriesing.de> |
743 |
|
|
* @param mixed (1) int the id of one element |
744 |
|
|
* (2) array an array of ids for which |
745 |
|
|
* the children will be returned |
746 |
|
|
* @param integer the children of how many levels shall be returned |
747 |
|
|
* @return mixed the array with the data of all children |
748 |
|
|
* or false, if there are none |
749 |
|
|
*/ |
750 |
joko |
1.2 |
function getChildren($ids,$levels=1) |
751 |
joko |
1.1 |
{ |
752 |
|
|
$res = array(); |
753 |
|
|
for( $i=1 ; $i<$levels+1 ; $i++ ) |
754 |
|
|
{ |
755 |
|
|
// if $ids is an array implode the values |
756 |
|
|
$getIds = is_array($ids) ? implode(',',$ids) : $ids; |
757 |
|
|
|
758 |
|
|
$query = sprintf( 'SELECT c.* FROM %s c,%s e WHERE%s e.%s=c.%s AND e.%s IN (%s) '. |
759 |
|
|
'ORDER BY c.%s', |
760 |
|
|
$this->table,$this->table, |
761 |
|
|
$this->_getWhereAddOn( ' AND ' , 'c' ), |
762 |
|
|
$this->_getColName('id'), |
763 |
|
|
$this->_getColName('parentId'), |
764 |
|
|
$this->_getColName('id'), |
765 |
|
|
$getIds, |
766 |
|
|
// order by left, so we have it in the order as it is in the tree |
767 |
|
|
// if no 'order'-option is given |
768 |
|
|
$this->getOption('order') ? $this->getOption('order') : $this->_getColName('left') |
769 |
|
|
); |
770 |
joko |
1.2 |
if (DB::isError($_res = $this->dbh->getAll($query))) { |
771 |
joko |
1.1 |
return $this->_throwError( $_res->getMessage() , __LINE__ ); |
772 |
|
|
} |
773 |
|
|
$_res = $this->_prepareResults( $_res ); |
774 |
|
|
|
775 |
|
|
// we use the id as the index, to make the use easier esp. for multiple return-values |
776 |
|
|
$tempRes = array(); |
777 |
joko |
1.2 |
foreach ($_res as $aRes) { |
778 |
joko |
1.1 |
$tempRes[$aRes[$this->_getColName('id')]] = $aRes; |
779 |
|
|
} |
780 |
|
|
$_res = $tempRes; |
781 |
|
|
|
782 |
|
|
// |
783 |
joko |
1.2 |
if ($levels>1) { |
784 |
joko |
1.1 |
$ids = array(); |
785 |
|
|
foreach( $_res as $aRes ) |
786 |
|
|
$ids[] = $aRes[$this->_getColName('id')]; |
787 |
|
|
} |
788 |
|
|
$res = array_merge($res,$_res); |
789 |
|
|
|
790 |
|
|
// quit the for-loop if there are no children in the current level |
791 |
joko |
1.2 |
if (!sizeof($ids)) { |
792 |
joko |
1.1 |
break; |
793 |
joko |
1.2 |
} |
794 |
joko |
1.1 |
} |
795 |
|
|
return $res; |
796 |
|
|
} |
797 |
|
|
|
798 |
|
|
/** |
799 |
|
|
* get the next element on the same level |
800 |
|
|
* if there is none return false |
801 |
|
|
* |
802 |
|
|
* @access public |
803 |
|
|
* @version 2002/04/15 |
804 |
|
|
* @author Wolfram Kriesing <wolfram@kriesing.de> |
805 |
|
|
* @param |
806 |
|
|
* @return mixed the array with the data of the next element |
807 |
|
|
* or false, if there is no next |
808 |
|
|
* or Tree_Error |
809 |
|
|
*/ |
810 |
|
|
function getNext( $id ) |
811 |
|
|
{ |
812 |
|
|
$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', |
813 |
|
|
$this->table,$this->table, |
814 |
|
|
$this->_getWhereAddOn( ' AND ' , 'n' ), |
815 |
|
|
$this->_getColName('right'), |
816 |
|
|
$this->_getColName('left'), |
817 |
|
|
$this->_getColName('parentId'), |
818 |
|
|
$this->_getColName('parentId'), |
819 |
|
|
$this->_getColName('id'), |
820 |
|
|
$id); |
821 |
|
|
if( DB::isError( $res = $this->dbh->getRow($query) ) ) |
822 |
|
|
{ |
823 |
|
|
return $this->_throwError( $res->getMessage() , __LINE__ ); |
824 |
|
|
} |
825 |
|
|
if( !$res ) |
826 |
|
|
return false; |
827 |
|
|
return $this->_prepareResult( $res ); |
828 |
|
|
} |
829 |
|
|
|
830 |
|
|
/** |
831 |
|
|
* get the previous element on the same level |
832 |
|
|
* if there is none return false |
833 |
|
|
* |
834 |
|
|
* @access public |
835 |
|
|
* @version 2002/04/15 |
836 |
|
|
* @author Wolfram Kriesing <wolfram@kriesing.de> |
837 |
|
|
* @param |
838 |
|
|
* @return mixed the array with the data of the previous element |
839 |
|
|
* or false, if there is no previous |
840 |
|
|
* or a Tree_Error |
841 |
|
|
*/ |
842 |
|
|
function getPrevious( $id ) |
843 |
|
|
{ |
844 |
|
|
$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', |
845 |
|
|
$this->table,$this->table, |
846 |
|
|
$this->_getWhereAddOn( ' AND ' , 'p' ), |
847 |
|
|
$this->_getColName('left'), |
848 |
|
|
$this->_getColName('right'), |
849 |
|
|
$this->_getColName('parentId'), |
850 |
|
|
$this->_getColName('parentId'), |
851 |
|
|
$this->_getColName('id'), |
852 |
|
|
$id); |
853 |
|
|
if( DB::isError( $res = $this->dbh->getRow($query) ) ) |
854 |
|
|
{ |
855 |
|
|
return $this->_throwError( $res->getMessage() , __LINE__ ); |
856 |
|
|
} |
857 |
|
|
if( !$res ) |
858 |
|
|
return false; |
859 |
|
|
return $this->_prepareResult( $res ); |
860 |
|
|
} |
861 |
|
|
|
862 |
|
|
/** |
863 |
|
|
* returns if $childId is a child of $id |
864 |
|
|
* |
865 |
|
|
* @abstract |
866 |
|
|
* @version 2002/04/29 |
867 |
|
|
* @access public |
868 |
|
|
* @author Wolfram Kriesing <wolfram@kriesing.de> |
869 |
|
|
* @param int id of the element |
870 |
|
|
* @param int id of the element to check if it is a child |
871 |
|
|
* @return boolean true if it is a child |
872 |
|
|
*/ |
873 |
|
|
function isChildOf( $id , $childId ) |
874 |
|
|
{ |
875 |
|
|
// check simply if the left and right of the child are within the |
876 |
|
|
// left and right of the parent, if so it definitly is a child :-) |
877 |
joko |
1.2 |
$parent = $this->getElement($id); |
878 |
|
|
$child = $this->getElement($childId); |
879 |
joko |
1.1 |
|
880 |
|
|
if( $parent['left'] < $child['left'] && |
881 |
|
|
$parent['right'] > $child['right'] ) |
882 |
|
|
{ |
883 |
|
|
return true; |
884 |
|
|
} |
885 |
|
|
|
886 |
|
|
return false; |
887 |
|
|
} // end of function |
888 |
|
|
|
889 |
joko |
1.2 |
/** |
890 |
|
|
* return the maximum depth of the tree |
891 |
|
|
* |
892 |
|
|
* @version 2003/02/25 |
893 |
|
|
* @access public |
894 |
|
|
* @author Wolfram Kriesing <wolfram@kriesing.de> |
895 |
|
|
* @return int the depth of the tree |
896 |
|
|
*/ |
897 |
|
|
function getDepth() |
898 |
|
|
{ |
899 |
|
|
// FIXXXME TODO!!! |
900 |
|
|
return $this->_throwError( 'not implemented yet' , __LINE__ ); |
901 |
|
|
} |
902 |
joko |
1.1 |
|
903 |
joko |
1.2 |
/** |
904 |
|
|
* Tells if the node with the given ID has children. |
905 |
|
|
* |
906 |
|
|
* @version 2003/03/04 |
907 |
|
|
* @access public |
908 |
|
|
* @author Wolfram Kriesing <wolfram@kriesing.de> |
909 |
|
|
* @param integer the ID of a node |
910 |
|
|
* @return boolean if the node with the given id has children |
911 |
|
|
*/ |
912 |
|
|
function hasChildren($id) |
913 |
|
|
{ |
914 |
|
|
$element = $this->getElement($id); |
915 |
|
|
return $element['right']-$element['left']>1; // if the diff between left and right>1 then there are children |
916 |
|
|
} |
917 |
joko |
1.1 |
|
918 |
|
|
|
919 |
|
|
// |
920 |
|
|
// PRIVATE METHODS |
921 |
|
|
// |
922 |
|
|
|
923 |
|
|
|
924 |
|
|
/** |
925 |
|
|
* |
926 |
|
|
* |
927 |
|
|
* @access private |
928 |
|
|
* @version 2002/04/20 |
929 |
|
|
* @author Wolfram Kriesing <wolfram@kriesing.de> |
930 |
|
|
* @param string the current where clause |
931 |
|
|
* @return |
932 |
|
|
*/ |
933 |
|
|
function _getWhereAddOn( $addAfter=' AND ' , $tableName='' ) |
934 |
|
|
{ |
935 |
|
|
if( $where=$this->getOption('whereAddOn') ) |
936 |
|
|
{ |
937 |
|
|
return ' '.($tableName?$tableName.'.':'')." $where$addAfter "; |
938 |
|
|
} |
939 |
|
|
return ''; |
940 |
|
|
} |
941 |
|
|
|
942 |
|
|
|
943 |
|
|
|
944 |
|
|
|
945 |
|
|
// for compatibility to Memory methods |
946 |
|
|
function getFirstRoot() |
947 |
|
|
{ |
948 |
|
|
return $this->getRoot(); |
949 |
|
|
} |
950 |
|
|
/** |
951 |
|
|
* gets the tree under the given element in one array, sorted |
952 |
|
|
* so you can go through the elements from begin to end and list them |
953 |
|
|
* as they are in the tree, where every child (until the deepest) is retreived |
954 |
|
|
* |
955 |
|
|
* @see &_getNode() |
956 |
|
|
* @access public |
957 |
|
|
* @version 2001/12/17 |
958 |
|
|
* @author Wolfram Kriesing <wolfram@kriesing.de> |
959 |
|
|
* @param integer $startId the id where to start walking |
960 |
|
|
* @param integer $depth this number says how deep into the structure the elements shall be retreived |
961 |
|
|
* @return array sorted as listed in the tree |
962 |
|
|
*/ |
963 |
|
|
function &getNode( $startId=0 , $depth=0 ) |
964 |
|
|
{ |
965 |
|
|
} |
966 |
|
|
|
967 |
|
|
} |
968 |
|
|
?> |