Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

> Drzewko left-right, Klasa, PHP 5
bela
post 29.08.2005, 13:10:57
Post #1


Administrator PHPedia.pl


Grupa: Developerzy
Postów: 1 102
Pomógł: 2
Dołączył: 14.09.2003

Ostrzeżenie: (0%)
-----


  1. <?php
  2. class Tree {
  3. /**
  4.  * Instance of Creole
  5.  */
  6. private $db;
  7.  
  8. /**
  9.  * Constructor, initialize Creole
  10.  *
  11.  * @param $dsn
  12.  */
  13. public function __construct($dsn) {
  14. $this->db = Creole::getConnection($dsn);;
  15. }
  16.  
  17. /**
  18.  * Adds node to tree
  19.  *
  20.  * @param object_id Id of object in system (this is not db id)
  21.  * @param parent Id of parent - db id
  22.  */
  23. public function addNode($object_id, $parent) {
  24. $rs = $this->db->executeQuery('SELECT `id`, `left`, `right` FROM tree WHERE `id`="' . $parent . '"');
  25. if($rs->getRecordCount() == 0) {
  26. $left = 1;
  27. $right = 2;
  28. } else {
  29. while($rs->next()) {
  30. $left = $rs->getInt('left');
  31. $right = $rs->getInt('right');
  32. $parentId = $rs->getInt('id');
  33. }
  34. }
  35. $sql = 'UPDATE tree SET `right` = `right` +2 WHERE `right` >' . ($right - 1);
  36. $this->db->executeQuery($sql);
  37.  
  38. $sql = 'UPDATE tree SET `left` = `left` +2 WHERE `left` > '. ($right - 1);
  39. $this->db->executeQuery($sql);
  40.  
  41. $sql = 'INSERT INTO tree SET `left`=' . ($right - 1) .', `right`=' . $right . ', `object_id`="'. $object_id .'", `parent_id`="' . $parentId .'";';
  42. $this->db->executeQuery($sql);
  43. }
  44.  
  45. /**
  46.  * Adds root node
  47.  *
  48.  * @param object_id Id of object in system (this is not db id)
  49.  * @return boolean
  50.  */
  51. public function addRoot($object_id) {
  52. $rs = $this->db->executeQuery('SELECT * FROM `tree` WHERE `parent_id` ="0"');
  53. if($rs->getRecordCount() == 0) {
  54. $this->db->executeQuery('INSERT INTO `tree` ( `id` , `object_id` , `left` , `right` ) VALUES ( '0', '' . $object_id . '', '1', '2')');
  55. return true;
  56. }
  57. return false;
  58. }
  59.  
  60. /**
  61.  * Removes node
  62.  *
  63.  * @param $id Id of node
  64.  */
  65. public function deleteNode($id) {
  66. $rs = $this->db->executeQuery('SELECT `parent_id`, `left` FROM `tree` WHERE `id`="'. $id .'"');
  67. while($rs->next()) {
  68. $node = array();
  69. $node['parent'] = $rs->getInt('parent_id');
  70. $node['left'] = $rs->getInt('left');
  71. }
  72.  
  73. $this->db->executeQuery('DELETE FROM `tree` WHERE `id`="' . $id . '" LIMIT 1');
  74. $this->rebuild($node['parent'], $node['left'] - 1);
  75. }
  76.  
  77. /**
  78.  * Rebuilds tree recursively
  79.  * If something goes wrong, you'll use this
  80.  *
  81.  * @param $parent Id of parent node
  82.  * @param $left Left
  83.  */
  84. public function rebuild($parent, $left) {
  85. $right = $left+1;
  86.  
  87. $rs = $this->db->executeQuery('SELECT `id` FROM `tree` WHERE `parent_id`="' . $parent . '";');
  88. while ($rs->next()) {
  89. $right = $this->rebuild($rs->getInt('id'), $right);
  90. }
  91. $this->db->executeQuery('UPDATE tree SET `left`=' . $left . ', `right`=' . $right . ' WHERE `id`="' . $parent . '";');
  92. return $right+1;
  93. }
  94.  
  95. /**
  96.  * Test method
  97.  *
  98.  * @param $root Id of node which is root to display
  99.  */
  100. function display($root) {
  101. $rs = $this->db->executeQuery('SELECT `left`, `right` FROM `tree` WHERE `id`="'.$root.'";');
  102. while($rs->next()) {
  103. $l = $rs->getInt('left');
  104. $r = $rs->getInt('right');
  105. }
  106.  
  107. $right = array();
  108.  
  109. $rs = $this->db->executeQuery('SELECT `object_id`, `left`, `right` FROM tree WHERE `left` BETWEEN '. $l .' AND ' . $r . ' ORDER BY `left` ASC;');
  110. while ($rs->next()) {
  111. if (count($right)>0) {
  112.  while ($right[count($right)-1] < $rs->getInt('right')) {
  113.  array_pop($right);
  114.  }
  115.  }
  116.  echo str_repeat('&nbsp;&nbsp;&nbsp;',count($right)) . $rs->getString('object_id'). ' Left: ' . $rs->getInt('left') . ' Right: '. $rs->getInt('right') . "<br/>n";
  117.  
  118.  $right[] = $rs->getInt('right');
  119.  }
  120. }
  121.  
  122. /**
  123.  * Gets object id
  124.  *
  125.  * @param id of node
  126.  * @return object id
  127.  */
  128. public function getNode($id) {
  129. $rs = $this->db->executeQuery('SELECT `object_id` FROM `tree` WHERE `id`="'.$id.'";');
  130. while($rs->next()) {
  131. return $rs->getInt('object_id');
  132. }
  133. }
  134. }
  135. ?>


  1. CREATE TABLE `tree` (
  2. `id` int(11) NOT NULL AUTO_INCREMENT,
  3. `parent_id` int(11) NOT NULL DEFAULT '0',
  4. `object_id` int(11) NOT NULL DEFAULT '0',
  5. `left` int(11) NOT NULL DEFAULT '0',
  6. `right` int(11) NOT NULL DEFAULT '0',
  7. PRIMARY KEY (`id`)
  8. ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=3 ;


Może komuś się przyda.
Object_id to nr obiektu w cmsie, równie dobrze możecie zastąpić to przez jakiś TEXT.


--------------------
Go to the top of the page
+Quote Post
 
Start new topic
Odpowiedzi (1 - 9)
mike
post 29.08.2005, 13:17:04
Post #2





Grupa: Przyjaciele php.pl
Postów: 7 494
Pomógł: 302
Dołączył: 31.03.2004

Ostrzeżenie: (0%)
-----


Przyznam że nawet nie zagłębiałem się w kod.
Jedyne co na starcie mi się nasuwa, że to może cos o drzewach binarnych tongue.gif

Dlatego cytat stąd:
Cytat
Autor musi jasno okreslic do czego służy klasa, funkcja lub algorytm i jak go używać (nie wklejamy tylko kodu).

@bella_666 możesz troszkę obkomentować?
Go to the top of the page
+Quote Post
bela
post 29.08.2005, 13:27:14
Post #3


Administrator PHPedia.pl


Grupa: Developerzy
Postów: 1 102
Pomógł: 2
Dołączył: 14.09.2003

Ostrzeżenie: (0%)
-----


Tyle o drzewkach piszą wokół, aż trudno nie słyszeć, ale co tam.
Proponuję lekturę http://www.sitepoint.com/article/hierarchical-data-database bo nie lubię się powtarzać.


--------------------
Go to the top of the page
+Quote Post
ebe
post 29.08.2005, 13:29:55
Post #4





Grupa: Zarejestrowani
Postów: 150
Pomógł: 1
Dołączył: 23.01.2004

Ostrzeżenie: (0%)
-----


Metoda display jest kompletnie bezużyteczna narzucasz sposób prezentacji drzewa, pozatym przydałaby się kolumna pozycjonująca elementy w gałęzi i metody do jej obsługi.

UPDATE zauważyłem że display to tylko metoda dotestowania biggrin.gif, tak więc jak proponujesz rozwiązania do np. prezentacji drzewa w formie menu? Np. ktoś chciałby sobie wstawić takie menu w <ul><li> a ktoś np. w <table> i jak zbudować seryjnie i wydajnie obiekty powiązane z poszczególnymi gałęziami...

Ten post edytował ebe 29.08.2005, 13:32:24


--------------------
Słyszałem, że macie tutaj jakieś takie php... fajne to, dobre to jest?
Go to the top of the page
+Quote Post
bela
post 29.08.2005, 13:46:19
Post #5


Administrator PHPedia.pl


Grupa: Developerzy
Postów: 1 102
Pomógł: 2
Dołączył: 14.09.2003

Ostrzeżenie: (0%)
-----


Fajnie, że zwróciłeś na to uwagę, jak wróce z treningu to się tym zajmę snitch.gif


--------------------
Go to the top of the page
+Quote Post
Bakus
post 31.08.2005, 21:18:38
Post #6


Administrator serwera


Grupa: Przyjaciele php.pl
Postów: 909
Pomógł: 0
Dołączył: 12.08.2003
Skąd: /var/www/wroclaw.php

Ostrzeżenie: (0%)
-----


Poprawiłem temat by był zgodny z nowymi zasadami na forum.


--------------------
Powrót do przeszłości :)
Go to the top of the page
+Quote Post
wiechol
post 4.05.2008, 14:33:22
Post #7





Grupa: Zarejestrowani
Postów: 8
Pomógł: 0
Dołączył: 12.03.2006

Ostrzeżenie: (0%)
-----


Witam,

Bawił sie już ktoś przenoszeniem węzłów?

Pozdrawiam
Go to the top of the page
+Quote Post
sf
post 4.05.2008, 14:49:07
Post #8





Grupa: Zarejestrowani
Postów: 1 597
Pomógł: 30
Dołączył: 19.02.2003
Skąd: Tychy

Ostrzeżenie: (0%)
-----


Tutaj jest lepsza klasa : http://www.phpriot.com/articles/nested-trees-appendix , która ma już zaimplementowaną odbudowę całego drzewa po przeniesieniu elementu.


--------------------
Zapraszam na mój php blog, tworzenie stron.
Go to the top of the page
+Quote Post
Crozin
post 4.05.2008, 16:02:41
Post #9





Grupa: Zarejestrowani
Postów: 6 476
Pomógł: 1306
Dołączył: 6.08.2006
Skąd: Kraków

Ostrzeżenie: (0%)
-----


Mógłbyś chociaż dodać możliwość przenoszenia (góra/dół) elementów po drzewku:
  1. <?php
  2. public function moveNodes($row, $direction){
  3. $parentID = is_null($row->{$this->parentID}) ? ' IS NULL ' : ' = ' . $row->{$this->parentID} . ' ';
  4.  
  5. $query = 'SELECT ' . $this->id .', ' . $this->left . ', ' . $this->right . 
  6.  ' FROM ' . $this->table . 
  7.  ' WHERE ' . $this->parentID . $parentID . 
  8.  ' AND ' . 
  9.  (($direction == 'up') ? $this->right . ' < ' . $row->{$this->right} . 
  10.  ' ORDER BY ' . $this->right . ' DESC' 
  11.  : $this->left . ' > ' . $row->{$this->left} .
  12.  ' ORDER BY ' . $this->left . ' ASC') .
  13.  ' LIMIT 1;';
  14.  
  15. $target = $this->db->getRow($query);
  16. if(!$target)
  17. return false;
  18.  
  19. if($direction == 'up'){
  20. $leftID = $target->{$this->left};
  21. $rightID = $row->{$this->right};
  22.  
  23. $diffUp = $row->{$this->left} - $target->{$this->left};
  24. $diffDown = $row->{$this->right} + 1 - $row->{$this->left};
  25.  
  26. $moveUpLeft = $row->{$this->left};
  27. $moveUpRight = $row->{$this->right};
  28. }else{
  29. $leftID = $row->{$this->left};
  30. $rightID = $target->{$this->right};
  31.  
  32. $diffUp = $row->{$this->right} + 1 - $row->{$this->left};
  33. $diffDown = $target->{$this->right} - $row->{$this->right};
  34.  
  35. $moveUpLeft = $row->{$this->right} + 1;
  36. $moveUpRight = $target->{$this->right};
  37. }
  38.  
  39. $query = 'UPDATE ' . $this->table . 
  40.  ' SET ' . $this->left . ' = ' . $this->left . ' + CASE' .
  41. ' WHEN ' . $this->left . ' BETWEEN ' . $moveUpLeft . ' AND ' . $moveUpRight .' THEN -' . $diffUp .
  42.  ' ELSE ' . $diffDown . 
  43.  ' END, ' .
  44.  $this->right . ' = ' . $this->right . ' + CASE' .
  45.  ' WHEN ' . $this->right . ' BETWEEN ' . $moveUpLeft . ' AND ' . $moveUpRight .' THEN -' . $diffUp .
  46.  ' ELSE ' . $diffDown .
  47.  ' END' .
  48.  ' WHERE ' . $this->left . ' BETWEEN ' . $leftID . ' AND ' . $rightID . 
  49. ' AND ' . $this->right . ' BETWEEN ' . $leftID . ' AND ' . $rightID . ';';
  50. $this->db->query($query);
  51.  
  52. return true;
  53. }
  54. ?>
I tak jeszcze w ramach objaśnienia:
  1. <?php
  2. $this->table; //nazwa tabeli przechowywujacej drzewko
  3. //nazwy pol w bazie (w konstruktorze klasy definujemy je sobie - nazwe tabeli tez)
  4. $this->id //np: moduleID
  5. $this->left 
  6. $this->right //np. treeRight
  7. $this->parentID
  8. $this->indent
  9. ?>



Metoda ta przyjmuje dwa argumenty - pierwszy to wynik zapytania pobierającego wszystko n/t elementu (node) którego chcemy przenieś. Drugi to string (up/down) - kierunek przesunięcia


EDIT: To wycinek z klasy gdzieś z początku 2007 (gdy zaczynałem OOP) - więc proszę bez zbednych komentarzy biggrin.gif

Ten post edytował Crozin 4.05.2008, 16:04:44
Go to the top of the page
+Quote Post
wiechol
post 4.05.2008, 17:39:54
Post #10





Grupa: Zarejestrowani
Postów: 8
Pomógł: 0
Dołączył: 12.03.2006

Ostrzeżenie: (0%)
-----


@Crozin

Twoja metoda zdaje się umożl
144d
iwia porządkowanie kolejności liści w węźle.

Mi chodziło o możliwość przenoszenia całych węzłów np mamy:

  1. Systemy operacyjne
  2. Rodzina windows
  3. Windows Vista
  4. Windows XP
  5. Windows XP Home
  6. Windows XP Professional
  7. Windows Server
  8. Rodzina UNIX
  9. Linux
  10. Ubunt
  11. Rodzina Apple


i chce sobie przenieść Windows XP do Rodziny Apple.

Rozwiązałem to już:


  1. <?php
  2. public function moveNode($currentNodeId, $destinationNodeId){
  3.  
  4. $currentResult = $this->db->query('SELECT id, rgt, rgt-lft+1 AS width FROM '.$this->table.' WHERE id='.$this->db->realEscapeString($currentNodeId));
  5. $currentRow = $currentResult->fetchRow();
  6. $c
  7. 1383
  8. urrentResult->free();
  9.  
  10. $destinationResult = $this->db->query('SELECT id, rgt FROM '.$this->table.' WHERE id='.$this->db->realEscapeString($destinationNodeId));
  11. $destinationRow = $destinationResult->fetchRow();
  12. $destinationResult->free();
  13.  
  14. $this->db->query('UPDATE '.$this->table.' SET rgt = rgt - '.$currentRow['width'].' WHERE rgt > '.$currentRow['rgt']);
  15. $this->db->query('UPDATE '.$this->table.' SET lft = lft - '.$currentRow['width'].' WHERE lft > '.$currentRow['rgt']);
  16.  
  17. $this->db->query('UPDATE '.$this->table.' SET rgt = rgt + '.$currentRow['width'].' WHERE rgt > '.$destinationRow['rgt']);
  18. $this->db->query('UPDATE '.$this->table.' SET lft = lft + '.$currentRow['width'].' WHERE lft > '.$destinationRow['rgt']);
  19.  
  20. $this->db->query('UPDATE '.$this->table.' SET parent_id = '.$destinationRow['id'].' WHERE id='.$currentRow['id']);
  21.  
  22. $this->_rebuildTree();
  23. }
  24.  
  25. protected function _rebuildTree($parent = 0, $left = 0, $level = 0) {
  26. $right = $left + 1;
  27.  
  28. $wynik = $this->db->query('SELECT id FROM '.$this->table.' WHERE parent_id='.$parent);
  29.  
  30. while ($row = $wynik->fetchRow()) {
  31. $right = $this->_rebuildTree($row['id'], $right, $level+1);
  32. }
  33.  
  34. $this->db->query('UPDATE '.$this->table.' SET lft = '.$left.', rgt = '.$right.', level = '.$level.' WHERE id='.$parent);
  35. return $right + 1;
  36. }
  37. ?>


Z chęcią zobaczę propozycje innych bo nie jestem zwolennikiem rekurencji

pozdrawiam
Go to the top of the page
+Quote Post

Reply to this topicStart new topic
1 Użytkowników czyta ten temat (1 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Wersja Lo-Fi Aktualny czas: 14.07.2025 - 18:51