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: Wolfram Kriesing <wolfram@kriesing.de> | |
17 |
// +----------------------------------------------------------------------+ |
18 |
// |
19 |
// $Id: Common.php,v 1.21 2003/03/04 18:59:21 cain Exp $ |
20 |
|
21 |
require_once('Tree/OptionsDB.php'); |
22 |
|
23 |
define("TREE_ERROR", -1); |
24 |
define("TREE_ERROR_INVALID_PARENT", -2); |
25 |
|
26 |
/** |
27 |
* common tree class, implements common functionality |
28 |
* |
29 |
* this class extends Tree_OptionsDB so every class that extends this oe can |
30 |
* connect to a db and set options |
31 |
* |
32 |
* @access public |
33 |
* @author Wolfram Kriesing <wolfram@kriesing.de> |
34 |
* @version 2001/06/27 |
35 |
* @package Tree |
36 |
*/ |
37 |
class Tree_Common extends Tree_OptionsDB |
38 |
{ |
39 |
|
40 |
/** |
41 |
* put proper value-keys are given in each class, depending on the implementation |
42 |
* only some options are needed or allowed, see the classes which extend this one |
43 |
* |
44 |
* @access public |
45 |
* @var array saves the options passed to the constructor |
46 |
*/ |
47 |
var $options = array(); |
48 |
|
49 |
|
50 |
/** |
51 |
* |
52 |
* |
53 |
* @version 2002/01/18 |
54 |
* @access public |
55 |
* @author Wolfram Kriesing <wolfram@kriesing.de> |
56 |
*/ |
57 |
function getChildId( $id ) |
58 |
{ |
59 |
$child = $this->getChild( $id ); |
60 |
return $child['id']; |
61 |
} |
62 |
|
63 |
/** |
64 |
* get the ids of the children of the given element |
65 |
* |
66 |
* @version 2002/02/06 |
67 |
* @access public |
68 |
* @author Wolfram Kriesing <wolfram@kriesing.de> |
69 |
* @param integer $id ID of the element that the children shall be retreived for |
70 |
* @param integer how many levels deep into the tree |
71 |
* @return mixed an array of all the ids of the children of the element with id=$id, |
72 |
* or false if there are no children |
73 |
*/ |
74 |
function getChildrenIds($id,$levels=1) |
75 |
{ |
76 |
if (!($children = $this->getChildren($id,$levels))) { // returns false if no children exist |
77 |
return array(); // return an empty array, if you want to know if there are children, use hasChildren |
78 |
} |
79 |
|
80 |
if ($children && sizeof($children)) { |
81 |
foreach ($children as $aChild) { |
82 |
$childrenIds[] = $aChild['id']; |
83 |
} |
84 |
} |
85 |
|
86 |
return $childrenIds; |
87 |
} |
88 |
|
89 |
/** |
90 |
* gets all the children and grand children etc. |
91 |
* |
92 |
* @version 2002/09/30 |
93 |
* @access public |
94 |
* @author Wolfram Kriesing <wolfram@kriesing.de> |
95 |
* @param integer $id ID of the element that the children shall be retreived for |
96 |
* @return mixed an array of all the children of the element with id=$id, |
97 |
* or false if there are no children |
98 |
*/ |
99 |
// FIXXXME remove this method and replace it by getChildren($id,0) |
100 |
function getAllChildren($id) |
101 |
{ |
102 |
$retChildren = false; |
103 |
if ($children = $this->hasChildren($id)) { |
104 |
$retChildren = $this->_getAllChildren( $id ); |
105 |
} |
106 |
return $retChildren; |
107 |
} |
108 |
|
109 |
/** |
110 |
* this method gets all the children recursively |
111 |
* |
112 |
* @see getAllChildren() |
113 |
* @version 2002/09/30 |
114 |
* @access public |
115 |
* @author Wolfram Kriesing <wolfram@kriesing.de> |
116 |
* @param integer $id ID of the element that the children shall be retreived for |
117 |
* @return mixed an array of all the ids of the children of the element with id=$id, |
118 |
* or false if there are no children |
119 |
*/ |
120 |
function &_getAllChildren($id) |
121 |
{ |
122 |
$retChildren = array(); |
123 |
if ($children = $this->getChildren($id)) { |
124 |
foreach ($children as $key=>$aChild) { |
125 |
$retChildren[] = &$children[$key]; |
126 |
$retChildren = array_merge($retChildren,$this->_getAllChildren( $aChild['id'] )); |
127 |
} |
128 |
} |
129 |
return $retChildren; |
130 |
} |
131 |
|
132 |
/** |
133 |
* gets all the children-ids and grand children-ids |
134 |
* |
135 |
* @version 2002/09/30 |
136 |
* @access public |
137 |
* @author Wolfram Kriesing <wolfram@kriesing.de> |
138 |
* @param integer $id ID of the element that the children shall be retreived for |
139 |
* @return mixed an array of all the ids of the children of the element with id=$id, |
140 |
* or false if there are no children |
141 |
*/ |
142 |
function getAllChildrenIds( $id ) |
143 |
{ |
144 |
$childrenIds = array(); |
145 |
if( $allChildren = $this->getAllChildren($id) ) |
146 |
{ |
147 |
$childrenIds = array(); |
148 |
foreach( $allChildren as $aNode ) |
149 |
$childrenIds[] = $aNode['id']; |
150 |
} |
151 |
return $childrenIds; |
152 |
} |
153 |
/** |
154 |
* get the id of the parent for the given element |
155 |
* |
156 |
* @version 2002/01/18 |
157 |
* @access public |
158 |
* @param integer $id the id of the element for which the parentId shall be retreived |
159 |
* @author Wolfram Kriesing <wolfram@kriesing.de> |
160 |
*/ |
161 |
function getParentId( $id ) |
162 |
{ |
163 |
$parent = $this->getParent( $id ); |
164 |
return $parent['id']; |
165 |
} |
166 |
|
167 |
/** |
168 |
* this gets all the preceeding nodes, the parent and it's parent and so on |
169 |
* |
170 |
* @version 2002/08/19 |
171 |
* @access public |
172 |
* @author Wolfram Kriesing <wolfram@kriesing.de> |
173 |
* @param integer $id the id of the element for which the parentId shall be retreived |
174 |
* @return array of the parent nodes including the node with id $id |
175 |
*/ |
176 |
function getParents( $id ) |
177 |
{ |
178 |
$path = $this->getPath($id); |
179 |
$parents = array(); |
180 |
if( sizeof($path) ) |
181 |
foreach( $path as $aNode ) |
182 |
$parents[] = $aNode; |
183 |
return $parents; |
184 |
} |
185 |
|
186 |
/** |
187 |
* get the ids of the parents and all it's parents and so on |
188 |
* it simply returns the ids of the elements returned by getParents() |
189 |
|
190 |
* @see getParents() |
191 |
* @version 2002/08/19 |
192 |
* @access public |
193 |
* @author Wolfram Kriesing <wolfram@kriesing.de> |
194 |
* @param integer $id the id of the element for which the parentId shall be retreived |
195 |
* @return array of the ids |
196 |
*/ |
197 |
function getParentsIds( $id ) |
198 |
{ |
199 |
$parents = $this->getParents($id); |
200 |
$parentsIds = array(); |
201 |
if( sizeof($parents) ) |
202 |
foreach( $parents as $aNode ) |
203 |
$parentsIds[] = $aNode['id']; |
204 |
return $parentsIds; |
205 |
} |
206 |
|
207 |
/** |
208 |
* |
209 |
* |
210 |
* @version 2002/01/18 |
211 |
* @access public |
212 |
* @author Wolfram Kriesing <wolfram@kriesing.de> |
213 |
*/ |
214 |
function getNextId( $id ) |
215 |
{ |
216 |
$next = $this->getNext( $id ); |
217 |
return $next['id']; |
218 |
} |
219 |
|
220 |
/** |
221 |
* |
222 |
* |
223 |
* @version 2002/01/18 |
224 |
* @access public |
225 |
* @author Wolfram Kriesing <wolfram@kriesing.de> |
226 |
*/ |
227 |
function getPreviousId( $id ) |
228 |
{ |
229 |
$previous = $this->getPrevious( $id ); |
230 |
return $previous['id']; |
231 |
} |
232 |
|
233 |
/** |
234 |
* |
235 |
* |
236 |
* @version 2002/01/18 |
237 |
* @access public |
238 |
* @author Wolfram Kriesing <wolfram@kriesing.de> |
239 |
*/ |
240 |
function getLeftId( $id ) |
241 |
{ |
242 |
$left = $this->getLeft( $id ); |
243 |
return $left['id']; |
244 |
} |
245 |
|
246 |
/** |
247 |
* |
248 |
* |
249 |
* @version 2002/01/18 |
250 |
* @access public |
251 |
* @author Wolfram Kriesing <wolfram@kriesing.de> |
252 |
*/ |
253 |
function getRightId( $id ) |
254 |
{ |
255 |
$right = $this->getRight( $id ); |
256 |
return $right['id']; |
257 |
} |
258 |
|
259 |
/** |
260 |
* |
261 |
* |
262 |
* @version 2002/01/18 |
263 |
* @access public |
264 |
* @author Wolfram Kriesing <wolfram@kriesing.de> |
265 |
*/ |
266 |
function getFirstRootId() |
267 |
{ |
268 |
$firstRoot = $this->getFirstRoot(); |
269 |
return $firstRoot['id']; |
270 |
} |
271 |
|
272 |
/** |
273 |
* |
274 |
* |
275 |
* @version 2002/04/16 |
276 |
* @access public |
277 |
* @author Wolfram Kriesing <wolfram@kriesing.de> |
278 |
*/ |
279 |
function getRootId() |
280 |
{ |
281 |
$firstRoot = $this->getRoot(); |
282 |
return $firstRoot['id']; |
283 |
} |
284 |
|
285 |
/** |
286 |
* returns the path as a string |
287 |
* |
288 |
* @access public |
289 |
* @version 2002/03/28 |
290 |
* @access public |
291 |
* @author Wolfram Kriesing <wolfram@kriesing.de> |
292 |
* @param mixed $id the id of the node to get the path for |
293 |
* @param integer If offset is positive, the sequence will |
294 |
* start at that offset in the array . If |
295 |
* offset is negative, the sequence will start that far from the end of the array . |
296 |
* @param integer If length is given and is positive, then |
297 |
* the sequence will have that many elements in it. If |
298 |
* length is given and is negative then the |
299 |
* sequence will stop that many elements from the end of the |
300 |
* array. If it is omitted, then the sequence will have everything |
301 |
* from offset up until the end of the array. |
302 |
* @return array this array contains all elements from the root to the element given by the id |
303 |
* |
304 |
*/ |
305 |
function getPathAsString( $id , $seperator='/' , $offset=0 , $length=0 ) |
306 |
{ |
307 |
$path = $this->getPath($id); |
308 |
foreach ($path as $aNode) { |
309 |
$pathArray[] = $aNode['name']; |
310 |
} |
311 |
|
312 |
if ($offset) { |
313 |
if ($length) { |
314 |
$pathArray = array_slice($pathArray,$offset,$length); |
315 |
} else { |
316 |
$pathArray = array_slice($pathArray,$offset); |
317 |
} |
318 |
} |
319 |
|
320 |
$pathString = ''; |
321 |
if( sizeof($pathArray) ) |
322 |
$pathString = implode($seperator,$pathArray); |
323 |
return $pathString; |
324 |
} // end of function |
325 |
|
326 |
|
327 |
|
328 |
|
329 |
|
330 |
|
331 |
// |
332 |
// abstract methods, those should be overwritten by the implementing class |
333 |
// |
334 |
|
335 |
|
336 |
/** |
337 |
* gets the path to the element given by its id |
338 |
* |
339 |
* @abstract |
340 |
* @version 2001/10/10 |
341 |
* @access public |
342 |
* @author Wolfram Kriesing <wolfram@kriesing.de> |
343 |
* @param mixed $id the id of the node to get the path for |
344 |
* @return array this array contains all elements from the root to the element given by the id |
345 |
* |
346 |
*/ |
347 |
function getPath( $id ) |
348 |
{ |
349 |
return $this->_throwError( 'not implemented, at least not overwritten the abstract declaration' , __LINE__ ); |
350 |
} // end of function |
351 |
|
352 |
/** |
353 |
* get the level, which is how far below the root the element with the given id is |
354 |
* |
355 |
* @abstract |
356 |
* @version 2001/11/25 |
357 |
* @access public |
358 |
* @author Wolfram Kriesing <wolfram@kriesing.de> |
359 |
* @param mixed $id the id of the node to get the level for |
360 |
* |
361 |
*/ |
362 |
function getLevel( $id ) |
363 |
{ |
364 |
return $this->_throwError( 'not implemented, at least not overwritten the abstract declaration' , __LINE__ ); |
365 |
} // end of function |
366 |
|
367 |
/** |
368 |
* returns if $childId is a child of $id |
369 |
* |
370 |
* @abstract |
371 |
* @version 2002/04/29 |
372 |
* @access public |
373 |
* @author Wolfram Kriesing <wolfram@kriesing.de> |
374 |
* @param int id of the element |
375 |
* @param int id of the element to check if it is a child |
376 |
* @param boolean if this is true the entire tree below is checked |
377 |
* @return boolean true if it is a child |
378 |
*/ |
379 |
function isChildOf( $id , $childId , $checkAll=true ) |
380 |
{ |
381 |
return $this->_throwError( 'not implemented, at least not overwritten the abstract declaration' , __LINE__ ); |
382 |
} // end of function |
383 |
|
384 |
/** |
385 |
* return the maximum depth of the tree |
386 |
* |
387 |
* @version 2003/02/25 |
388 |
* @access public |
389 |
* @author Wolfram Kriesing <wolfram@kriesing.de> |
390 |
* @return int the depth of the tree |
391 |
*/ |
392 |
function getDepth() |
393 |
{ |
394 |
return $this->_treeDepth; |
395 |
} // end of function |
396 |
|
397 |
|
398 |
|
399 |
|
400 |
|
401 |
// |
402 |
// PRIVATE METHODS |
403 |
// |
404 |
|
405 |
|
406 |
/** |
407 |
* prepare multiple results |
408 |
* |
409 |
* @see _prepareResult() |
410 |
* @access private |
411 |
* @version 2002/03/03 |
412 |
* @author Wolfram Kriesing <wolfram@kriesing.de> |
413 |
* @param |
414 |
* @return |
415 |
*/ |
416 |
function _prepareResults( $results ) |
417 |
{ |
418 |
$newResults = array(); |
419 |
foreach( $results as $key=>$aResult ) |
420 |
$newResults[$key] = $this->_prepareResult($aResult); |
421 |
return $newResults; |
422 |
} |
423 |
|
424 |
/** |
425 |
* map back the index names to get what is expected |
426 |
* |
427 |
* @access private |
428 |
* @version 2002/03/03 |
429 |
* @author Wolfram Kriesing <wolfram@kriesing.de> |
430 |
* @param |
431 |
* @return |
432 |
*/ |
433 |
function _prepareResult( $result ) |
434 |
{ |
435 |
$map = $this->getOption('columnNameMaps'); |
436 |
|
437 |
if( $map ) |
438 |
foreach( $map as $key=>$columnName ) |
439 |
{ |
440 |
$result[$key] = $result[$columnName]; |
441 |
unset($result[$columnName]); |
442 |
} |
443 |
return $result; |
444 |
} |
445 |
|
446 |
/** |
447 |
* this method retreives the real column name, as used in the DB |
448 |
* since the internal names are fixed, to be portable between different |
449 |
* DB-column namings, we map the internal name to the real column name here |
450 |
* |
451 |
* @access private |
452 |
* @version 2002/03/02 |
453 |
* @author Wolfram Kriesing <wolfram@kriesing.de> |
454 |
* @param |
455 |
* @return |
456 |
*/ |
457 |
function _getColName( $internalName ) |
458 |
{ |
459 |
if( $map = $this->getOption( 'columnNameMaps' ) ) |
460 |
{ |
461 |
if( isset($map[$internalName]) ) |
462 |
return $map[$internalName]; |
463 |
} |
464 |
return $internalName; |
465 |
} |
466 |
|
467 |
/** |
468 |
* |
469 |
* |
470 |
* @access private |
471 |
* @version 2002/03/02 |
472 |
* @author Wolfram Kriesing <wolfram@kriesing.de> |
473 |
* @param |
474 |
* @return |
475 |
*/ |
476 |
function _throwError( $msg , $line , $mode=null ) |
477 |
{ |
478 |
if( $mode===null && $this->debug>0 ) |
479 |
$mode = PEAR_ERROR_PRINT; |
480 |
return new Tree_Error( $msg , $line , __FILE__ , $mode , $this->dbh->last_query ); |
481 |
} |
482 |
|
483 |
} |
484 |
?> |