1: <?php defined('_JOOS_CORE') or exit();
2:
3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
16: class joosNestedSet extends joosModel
17: {
18: 19: 20: 21: 22:
23: public $id;
24:
25: 26: 27: 28: 29:
30: public $lft;
31:
32: 33: 34: 35: 36:
37: public $rgt;
38:
39: 40: 41: 42: 43:
44: public $level;
45:
46: 47: 48: 49: 50:
51: public $parent_id;
52: public $moved;
53:
54: 55: 56: 57: 58:
59: public $name;
60:
61: 62: 63: 64: 65:
66: public $group;
67:
68: 69: 70: 71: 72:
73: public $slug;
74:
75: 76: 77: 78: 79:
80: private $params = array();
81:
82: 83: 84: 85: 86:
87: private $errors = array();
88:
89: 90: 91: 92: 93: 94: 95: 96:
97: public function __construct($params)
98: {
99: parent::__construct($params['table'], 'id');
100:
101: $this->params = array('nid' => 'id', 'l' => 'lft', 'r' => 'rgt', 'mov' => 'moved', 'name' => 'name');
102: }
103:
104: 105: 106: 107: 108: 109: 110:
111: public function insert_root_node($nodeName)
112: {
113:
114:
115: if ($this->check_root_node() === true) {
116: $error = 'Корневой узел уже существует. NestedSet::insert_root_node ("' . $nodeName . '")';
117: $this->_set_error($error);
118:
119: return false;
120: }
121:
122: $this->name = 'root';
123: $this->lft = 1;
124: $this->rgt = 2;
125: $this->level = 0;
126:
127: if ($this->store()) {
128: $error = 'Ошибка запроса к БД. NestedSet::insert_root_node ("' . $nodeName . '")';
129: $this->_set_error($error);
130:
131: return false;
132: }
133:
134: return true;
135: }
136:
137: 138: 139: 140: 141: 142: 143: 144:
145: public function save(array $source, $ignore = '')
146: {
147:
148: $parent = new self(array('table' => $this->_tbl));
149:
150: if (!$parent->load($source['parent_id'])) {
151: $error = 'Родительский узел не найден ("' . $source['parent_id'] . '")';
152: $this->_set_error($error);
153:
154: return false;
155: }
156:
157:
158: $sql = 'UPDATE ' . $this->_tbl . ' SET `rgt` = `rgt` + 2 WHERE `rgt` >= ' . $parent->rgt;
159: $this->_db->set_query($sql)->query();
160:
161: $sql = 'UPDATE ' . $this->_tbl . ' SET `lft` = `lft` + 2 WHERE `lft` > ' . $parent->rgt;
162: $this->_db->set_query($sql)->query();
163:
164: $this->lft = $parent->rgt;
165: $this->rgt = $parent->rgt + 1;
166: $this->level = $parent->level + 1;
167: $this->parent_id = $parent->id;
168:
169: parent::save($source, $ignore);
170:
171: return true;
172: }
173:
174: 175: 176: 177: 178: 179: 180:
181: public function delete_branch($id)
182: {
183: $branch = clone $this;
184:
185: if (!$branch->load($id)) {
186: $error = 'Требуемый узел не найден';
187: $this->_set_error($error);
188:
189: return false;
190: }
191:
192:
193: $branch->delete_list(array('where' => 'lft BETWEEN ' . $branch->lft . ' AND ' . $branch->rgt));
194:
195:
196: $sql = "UPDATE $this->_tbl SET lft = lft - ROUND(($branch->rgt - $branch->lft + 1)) WHERE lft > $branch->rgt";
197: $this->_db->set_query($sql)->query();
198:
199:
200: $sql = "UPDATE $this->_tbl SET rgt = rgt - ROUND(($branch->rgt - $branch->lft + 1)) WHERE rgt > $branch->rgt";
201: $this->_db->set_query($sql)->query();
202:
203: return true;
204: }
205:
206: 207: 208: 209: 210: 211: 212:
213: public function delete_node($id)
214: {
215: $node = clone $this;
216:
217: if (!$node->load($id)) {
218: $error = 'Требуемый узел не найден';
219: $this->_set_error($error);
220:
221: return false;
222: }
223:
224: $sql = "DELETE FROM $this->_tbl WHERE lft = $node->lft";
225: $this->_db->set_query($sql)->query();
226:
227: $sql = "UPDATE $this->_tbl SET lft = lft - 1, rgt = rgt - 1 WHERE lft BETWEEN $node->lft AND $node->rgt";
228: $this->_db->set_query($sql)->query();
229:
230: $sql = "UPDATE $this->_tbl SET lft = lft - 2 WHERE lft > $node->rgt";
231: $this->_db->set_query($sql)->query();
232:
233: $sql = "UPDATE $this->_tbl SET rgt = rgt - 2 WHERE rgt > $node->rgt";
234: $this->_db->set_query($sql)->query();
235:
236: return true;
237: }
238:
239: 240: 241: 242: 243: 244: 245:
246: public function move_lft($id)
247: {
248: $node = clone $this;
249:
250: if (!$node->load($id)) {
251: $error = 'Требуемый узел не найден';
252: $this->_set_error($error);
253:
254: return false;
255: }
256:
257: $a_lft = $node->lft;
258: $a_rgt = $node->rgt;
259:
260: if (!$b_id = $this->_get_id($a_lft - 1, 'r')) {
261: $error = 'Родственный узел слева не найден. NestedSet::move_lft (' . $id . ')';
262: $this->_set_error($error);
263:
264: return false;
265: }
266:
267: if (!$b = $this->_get_node($b_id)) {
268: $error = 'Родственный узел слева не найден. NestedSet::move_lft (' . $id . ')';
269: $this->_set_error($error);
270:
271: return false;
272: }
273:
274: $b_lft = $b['lft'];
275: $b_rgt = $b['rgt'];
276:
277: $diffRgt = $a_rgt - $b_rgt;
278: $diffLft = $a_lft - $b_lft;
279:
280: $sql = sprintf('UPDATE `%1$s` SET `%2$s` = %11$d WHERE `%2$s` <> %11$d', $this->_tbl, $this->params['mov'], 'rgt', 'lft', (int) $diffRgt, (int) $diffLft, (int) $a_lft, (int) $a_rgt, (int) $b_lft, (int) $b_rgt, 0, 1);
281: $this->_db->set_query($sql)->query();
282:
283: $sql = sprintf('UPDATE `%1$s` SET `%3$s` = `%3$s` + %5$d,`%4$s` = `%4$s` + %5$d,`%2$s` = %12$d WHERE `%4$s` BETWEEN %9$d AND %10$d', $this->_tbl, $this->params['mov'], 'rgt', 'lft', (int) $diffRgt, (int) $diffLft, (int) $a_lft, (int) $a_rgt, (int) $b_lft, (int) $b_rgt, 0, 1);
284: $this->_db->set_query($sql)->query();
285:
286: $sql = sprintf('UPDATE `%1$s` SET `%3$s` = `%3$s` - %6$d,`%4$s` = `%4$s` - %6$d WHERE `%4$s` BETWEEN %7$d AND %8$d AND `%2$s` = %11$d', $this->_tbl, $this->params['mov'], 'rgt', 'lft', (int) $diffRgt, (int) $diffLft, (int) $a_lft, (int) $a_rgt, (int) $b_lft, (int) $b_rgt, 0, 1);
287: $this->_db->set_query($sql)->query();
288:
289: $sql = sprintf('UPDATE `%1$s` SET`%2$s` = %11$d WHERE `%2$s` <> %11$d', $this->_tbl, $this->params['mov'], 'rgt', 'lft', (int) $diffRgt, (int) $diffLft, (int) $a_lft, (int) $a_rgt, (int) $b_lft, (int) $b_rgt, 0, 1);
290: $this->_db->set_query($sql)->query();
291:
292: return true;
293: }
294:
295: 296: 297: 298: 299: 300: 301:
302: public function move_rgt($nodeId)
303: {
304: $nodeLevel = $this->_get_node_level($nodeId);
305:
306: if ($nodeLevel == 0) {
307: $error = 'Это корневой узел, его нельзя перемещать. NestedSet::move_rgt (' . $nodeId . ' ' . $nodeLevel . ')';
308: $this->_set_error($error);
309:
310: return false;
311: }
312:
313: $a = $this->_get_node($nodeId);
314: $a_lft = $a['lft'];
315: $a_rgt = $a['rgt'];
316:
317: if (!$b_id = $this->_get_id($a_rgt + 1, 'l')) {
318: $error = 'Родственный узел справа не найден. NestedSet::move_rgt (' . $nodeId . ')';
319: $this->_set_error($error);
320:
321: return false;
322: }
323:
324: if (!$b = $this->_get_node($b_id)) {
325: $error = 'Родственный узел справа не найден. NestedSet::move_rgt (' . $nodeId . ')';
326: $this->_set_error($error);
327:
328: return false;
329: }
330:
331: $b_lft = $b['lft'];
332: $b_rgt = $b['rgt'];
333:
334: $diffRgt = $b_rgt - $a_rgt;
335: $diffLft = $b_lft - $a_lft;
336:
337: $sql = sprintf('UPDATE `%1$s` SET `%2$s` = %11$d WHERE `%2$s` <> %11$d', $this->_tbl, $this->params['mov'], 'lft', 'rgt', (int) $diffLft, (int) $diffRgt, (int) $b_lft, (int) $b_rgt, (int) $a_lft, (int) $a_rgt, 0, 1);
338: $this->_db->set_query($sql)->query();
339:
340: $sql = sprintf('UPDATE `%1$s` SET `%4$s` = `%4$s` - %5$d, `%3$s` = `%3$s` - %5$d, `%2$s` = %12$d WHERE `%3$s` BETWEEN %7$d AND %8$d', $this->_tbl, $this->params['mov'], 'lft', 'rgt', (int) $diffLft, (int) $diffRgt, (int) $b_lft, (int) $b_rgt, (int) $a_lft, (int) $a_rgt, 0, 1);
341: $this->_db->set_query($sql)->query();
342:
343: $sql = sprintf('UPDATE `%1$s` SET `%4$s` = `%4$s` + %6$d, `%3$s` = `%3$s` + %6$d WHERE `%3$s` BETWEEN %9$d AND %10$d AND `%2$s` = %11$d', $this->_tbl, $this->params['mov'], 'lft', 'rgt', (int) $diffLft, (int) $diffRgt, (int) $b_lft, (int) $b_rgt, (int) $a_lft, (int) $a_rgt, 0, 1);
344: $this->_db->set_query($sql)->query();
345:
346: $sql = sprintf('UPDATE `%1$s` SET `%2$s` = %11$d WHERE `%2$s` <> %11$d', $this->_tbl, $this->params['mov'], 'lft', 'rgt', (int) $diffLft, (int) $diffRgt, (int) $b_lft, (int) $b_rgt, (int) $a_lft, (int) $a_rgt, 0, 1);
347: $this->_db->set_query($sql)->query();
348:
349: return true;
350: }
351:
352: 353: 354: 355: 356: 357: 358:
359: public function move_up($nodeId)
360: {
361: $nodeLevel = $this->_get_node_level($nodeId);
362:
363:
364:
365: if ($nodeLevel == 0) {
366: $error = 'Это корневой узел, его нельзя перемещать. NestedSet::move_up (' . $nodeId . ')';
367: $this->_set_error($error);
368:
369: return false;
370: }
371:
372: if ($nodeLevel == 1) {
373: $error = 'Родственный узел справа не найден. NestedSet::move_up (' . $nodeId . ')';
374: $this->_set_error($error);
375:
376: return false;
377: }
378:
379: do {
380: if (!$moved = $this->move_rgt($nodeId)) {
381: break;
382: }
383: } while ($moved === true);
384:
385: $a = $this->_get_node($nodeId);
386: $a_lft = $a['lft'];
387: $a_rgt = $a['rgt'];
388:
389: if (!$b_id = $this->_get_id($a_rgt + 1, 'r')) {
390: $error = 'На корневной уровень нельзя переместиться. NestedSet::move_up (' . $nodeId . ')';
391: $this->_set_error($error);
392:
393: return false;
394: }
395:
396: if (!$b = $this->_get_node($b_id)) {
397: $error = 'На корневной уровень нельзя переместиться. NestedSet::move_up (' . $nodeId . ')';
398: $this->_set_error($error);
399:
400: return false;
401: }
402:
403:
404:
405:
406: $nodeWidth = $a_rgt - $a_lft + 1;
407:
408:
409: $sql = sprintf('UPDATE `%1$s` SET `%2$s` = `%2$s` + %9$d,`%3$s` = `%3$s` + %9$d, level = level - 1 WHERE `%3$s`BETWEEN %5$d AND %6$d', $this->_tbl, 'rgt', 'lft', $this->params['nid'], (int) $a_lft, (int) $a_rgt, (int) $nodeWidth, (int) $b_id, 1);
410: $this->_db->set_query($sql)->query();
411:
412:
413: $sql = sprintf('UPDATE `%1$s` SET `%2$s` = `%2$s` - %7$d WHERE `%4$s` = %8$d', $this->_tbl, 'rgt', 'lft', $this->params['nid'], (int) $a_lft, (int) $a_rgt, (int) $nodeWidth, (int) $b_id, 1);
414: $this->_db->set_query($sql)->query();
415:
416:
417: $a = $this->_get_node($nodeId);
418: $p_id = $this->get_parent($a)->id;
419: $sql = "UPDATE $this->_tbl SET parent_id = $p_id WHERE id = " . $nodeId;
420: $this->_db->set_query($sql)->query();
421:
422: return true;
423: }
424:
425: public function get_parent($child)
426: {
427: $sql = "SELECT * FROM $this->_tbl WHERE lft <= {$child['lft']} AND rgt >= {$child['rgt']} AND level = {$child['level']} - 1 ORDER BY lft";
428:
429: $result = null;
430: $this->_db->set_query($sql)->load_object($result);
431:
432: return $result;
433: }
434:
435: 436: 437: 438: 439: 440: 441:
442: public function move_down($nodeId)
443: {
444: $nodeLevel = $this->_get_node_level($nodeId);
445:
446: if ($nodeLevel == 1) {
447: $error = 'Это корневой узел, его нельзя перемещать. NestedSet::move_down (' . $nodeId . ')';
448: $this->_set_error($error);
449:
450: return false;
451: }
452:
453: $a = $this->_get_node($nodeId);
454: $a_lft = $a['lft'];
455: $a_rgt = $a['rgt'];
456:
457: if (!$b_id = $this->_get_id($a_lft - 1, 'r')) {
458: $error = 'Родственный узел слева не найден. NestedSet::move_down (' . $nodeId . ')';
459: $this->_set_error($error);
460:
461: return false;
462: }
463: if (!$b = $this->_get_node($b_id)) {
464: $error = 'Родственный узел слева не найден. NestedSet::move_down (' . $nodeId . ')';
465: $this->_set_error($error);
466:
467: return false;
468: }
469:
470:
471:
472:
473: $nodeWidth = $a_rgt - $a_lft + 1;
474:
475: $sql = sprintf('UPDATE `%1$s` SET `%2$s` = `%2$s` - %9$d, `%3$s` = `%3$s` - %9$d, level = level + 1 WHERE `%3$s` BETWEEN %5$d AND %6$d', $this->_tbl, 'rgt', 'lft', $this->params['nid'], (int) $a_lft, (int) $a_rgt, (int) $nodeWidth, (int) $b_id, 1);
476: $this->_db->set_query($sql)->query();
477:
478: $sql = sprintf('UPDATE `%1$s` SET parent_id = %8$d WHERE id = ' . $nodeId, $this->_tbl, 'rgt', 'lft', $this->params['nid'], (int) $a_lft, (int) $a_rgt, (int) $nodeWidth, (int) $b_id, 1);
479: $this->_db->set_query($sql)->query();
480:
481: $sql = sprintf('UPDATE `%1$s` SET `%2$s` = `%2$s` + %7$d WHERE `%4$s` = %8$d', $this->_tbl, 'rgt', 'lft', $this->params['nid'], (int) $a_lft, (int) $a_rgt, (int) $nodeWidth, (int) $b_id, 1);
482: $this->_db->set_query($sql)->query();
483:
484:
485: $a = $this->_get_node($nodeId);
486: $p_id = $this->get_parent($a)->id;
487: $sql = "UPDATE $this->_tbl SET parent_id = $p_id WHERE id = " . $nodeId;
488: $this->_db->set_query($sql)->query();
489:
490: return true;
491: }
492:
493: 494: 495: 496: 497:
498: public function check_root_node()
499: {
500: $sql = sprintf('SELECT `%1$s` FROM `%2$s` WHERE `%3$s` = %4$d', $this->params['nid'], $this->_tbl, 'lft', 1);
501: $this->_db->set_query($sql);
502:
503: if (!$result = $this->_db->query()) {
504: $error = 'Ошибка запроса к БД. NestedSet::check_root_node ()';
505: $this->_set_error($error);
506:
507: return false;
508: }
509:
510: if (!$result->num_rows) {
511: $error = 'Корневой узел не найден. NestedSet::check_root_node ()';
512: $this->_set_error($error);
513:
514: return false;
515: }
516:
517: return true;
518: }
519:
520: 521: 522: 523: 524:
525: public function is_error()
526: {
527: return (empty($this->errors)) ? false : true;
528: }
529:
530: 531: 532: 533: 534:
535: public function get_errors()
536: {
537: return (true === $this->is_error()) ? $this->errors : null;
538: }
539:
540: 541: 542: 543: 544:
545: public function get_full_tree_extended()
546: {
547: $where_group = $this->group ? ' AND n.group = "' . $this->group . '" ' : '';
548:
549: $sql = sprintf('SELECT
550: `%1$s`.*, round((`%1$s`.`%4$s` - `%1$s`.`%3$s` - %8$d) / %9$d, %7$d) AS childs,
551: n.level AS level,
552: ((min(`%2$s`.`%4$s`) - `%1$s`.`%4$s` - (`%1$s`.`%3$s` > %8$d)) / %9$d) > %7$d AS lower,
553: (((`%1$s`.`%3$s` - max(`%2$s`.`%3$s`) > %8$d))) AS upper
554: FROM `%5$s` `%1$s`, `%5$s` `%2$s`
555: WHERE
556: `%1$s`.`%3$s` BETWEEN `%2$s`.`%3$s`
557: AND `%2$s`.`%4$s` AND ( `%2$s`.`%6$s` != `%1$s`.`%6$s` OR `%1$s`.`%3$s` = %8$d )
558: ' . $where_group . '
559: GROUP BY `%1$s`.`%6$s`
560: ORDER BY `%1$s`.`%3$s`', 'n', 'p', 'lft', 'rgt', $this->_tbl, $this->params['nid'], 0, 1, 2);
561:
562: $this->_db->set_query($sql);
563:
564: return $this->_db->load_assoc_list();
565: }
566:
567: 568: 569: 570: 571:
572: public function get_full_tree_simple()
573: {
574: $where_group = $this->group ? ' WHERE `group` = "' . $this->group . '" ' : '';
575:
576: $this->_db->set_query("SELECT * FROM $this->_tbl $where_group ORDER BY lft ASC");
577:
578: $result = $this->_db->load_assoc_list('id');
579:
580: return $result ? $result : array();
581: }
582:
583: 584: 585: 586: 587: 588: 589: 590:
591: public function get_branch($lft, $rgt, $object_list = false)
592: {
593: $this->_db->set_query("SELECT *, round((rgt - lft - 1) / 2, 0) AS childs_count FROM $this->_tbl WHERE lft >= $lft AND rgt <= $rgt ORDER BY lft");
594:
595: return $object_list ? $this->_db->load_object_list('id') : $this->_db->load_assoc_list('id');
596:
597:
598: }
599:
600: 601: 602: 603: 604: 605: 606:
607: public function get_children($id, $object_list = false)
608: {
609: $this->_db->set_query("SELECT * FROM $this->_tbl WHERE parent_id = $id ORDER BY lft");
610:
611: return $object_list ? $this->_db->load_object_list('id') : $this->_db->load_assoc_list('id');
612:
613:
614: }
615:
616: 617: 618: 619: 620: 621: 622:
623: public function get_path_from_root($nodeId, $object_list = false)
624: {
625: $sql = "SELECT p.*
626: FROM $this->_tbl AS n, $this->_tbl AS p
627: WHERE p.lft <= n.lft AND p.rgt >= n.rgt AND n." . $this->params['nid'] . " = " . (int) $nodeId . "
628: ORDER BY p.lft";
629:
630: return $object_list ? $this->_db->set_query($sql)->load_object_list() : $this->_db->set_query($sql)->load_assoc_list('id');
631: }
632:
633: 634: 635: 636: 637: 638: 639: 640:
641: private function _get_id($directionValue, $direction)
642: {
643: $sql = sprintf('SELECT `%1$s` FROM `%2$s` WHERE `%3$s` = %4$d', $this->params['nid'], $this->_tbl, $this->params[$direction], (int) $directionValue);
644: $this->_db->set_query($sql);
645:
646: if (!$result = $this->_db->query()) {
647: $error = 'Ошибка запроса к БД. NestedSet::_get_id()';
648: $this->_set_error($error);
649:
650: return false;
651: }
652:
653: if (!$result->num_rows) {
654: $error = 'Невозможно получить информацию по предоставленным данным. NestedSet::_get_id()';
655: $this->_set_error($error);
656:
657: return false;
658: }
659:
660: $row = $result->fetch_assoc();
661:
662: return $row[$this->params['nid']];
663: }
664:
665: 666: 667: 668: 669: 670: 671:
672: private function _get_node($nodeId)
673: {
674: $sql = sprintf('SELECT `%1$s`,`%2$s`,`%3$s`, level FROM `%4$s` WHERE `%1$s` = %5$d', $this->params['nid'], 'lft', 'rgt', $this->_tbl, (int) $nodeId);
675: $this->_db->set_query($sql);
676:
677: if (!$result = $this->_db->query()) {
678: $error = 'Ошибка запроса к БД. NestedSet::_get_node()';
679: $this->_set_error($error);
680:
681: return false;
682: }
683:
684: if (!$result->num_rows) {
685: $error = 'Требуемый узел не найден. NestedSet::_get_node()';
686: $this->_set_error($error);
687:
688: return false;
689: }
690:
691: $row = $result->fetch_assoc();
692:
693: return $row;
694: }
695:
696: 697: 698: 699: 700: 701: 702:
703: private function _get_node_level($nodeId)
704: {
705: 706: 707: 708: 709: 710: 711: 712: 713: 714: 715: 716: 717: 718: 719: 720: 721: 722: 723: 724: 725: 726: 727: 728: 729: 730: 731:
732:
733: $query = 'SELECT level FROM `' . $this->_tbl . '` WHERE `' . $this->_tbl . '`.`' . $this->params['nid'] . '` = ' . (int) $nodeId;
734: if (!$result = $this->_db->set_query($query)->load_result()) {
735: return false;
736: }
737:
738: return $result;
739: }
740:
741: 742: 743: 744: 745:
746: private function _count_nodes()
747: {
748: $sql = sprintf('SELECT COUNT(`%1$s`) FROM `%2$s` AS `count`', $this->params['nid'], $this->_tbl);
749: $this->_db->set_query($sql);
750:
751: if (!$result = $this->_db->query()) {
752: $error = 'Ошибка запроса к БД. NestedSet::_count_nodes()';
753: $this->_set_error($error);
754:
755: return false;
756: }
757:
758: if (!$result->num_rows) {
759: $error = 'Узлы не найдены. NestedSet::_count_nodes()';
760: $this->_set_error($error);
761:
762: return false;
763: }
764:
765: $row = $result->fetch_assoc();
766:
767: return $row['count'];
768: }
769:
770: 771: 772: 773: 774: 775: 776:
777: private function _set_error($error)
778: {
779: $this->errors[] = $error;
780: }
781:
782: }
783:
784: class TreeBuilder
785: {
786: public $items = array();
787: public $children = array();
788:
789: public function __construct($items)
790: {
791: $this->items = $items;
792: $this->children = array();
793:
794: foreach ($items as $v) {
795: $list = isset($this->children[$v->parent_id]) ? $this->children[$v->parent_id] : array();
796: array_push($list, $v);
797: $this->children[$v->parent_id] = $list;
798: }
799:
800:
801: }
802:
803: public function build_tree($id, $list = array(), $maxlevel = 9999, $level = 0)
804: {
805: if (isset($this->children[$id]) && $level <= $maxlevel) {
806: $i = 1;
807:
808: foreach ($this->children[$id] as $v) {
809: $id = $v->id;
810:
811: if (isset($this->children[$id])) {
812: $list[$id] = $v;
813: $list[$id]->children = $this->children[$id];
814: $list = $this->build_tree($id, $list, $maxlevel, $level + 1);
815: } else {
816:
817: }
818:
819:
820:
821: $i++;
822: }
823:
824:
825: }
826:
827:
828:
829: return $list;
830: }
831:
832: }
833: