MySQL Nested Sets - Elternelement ändern

WhiZZler

Chancentod²
ID: 85586
L
6 Mai 2006
588
32
Begrüße!

wollte gerade den letzten teil meiner nested set implementation fertig schreiben, bin aber grade zu dem schluss gekommen, dass das härterer tobag ist, als ich dachte :D

und zwar geht es darum, einen eintrag von einem elternelement in ein anderes zu verschieben.. ich hab mir das grade mal in ner tabelle aufgemalt mit den lft und rgt werten in der originaltabelle und der tabelle, wie sie nach dem verschieben aussehen soll.. und habe festgestellt, dass die abhängigkeiten um einiges komplexer sind als ich erwartet hatte..

und bevor ich jetzt stunden und tage verschenke und versuche, das rad neu zu erfinden.. kennt hier jemand ne fertige implementation, die sowas kann? ich möchte eigentlich nur die arbeitsschritte wissen, also welche werte ich von welchen einträgen wie anpassen muss.. oder einen blogeintrag? oder irgendwas hilfreiches? ;)

google hat mir nicht sonderlich weitergeholfen.. mit "nested set change parent" oder ähnlichem komme ich nur auf seiten, die die funktionsweise allgemein erklären..

mfg
whizzler
 
PHP:
function verschieben($knoten, $toknotendata) {
        $this->pdo->query('LOCK TABLES '.$this->table.' WRITE');
        // Daten der Knoten auslesen
        $verschiebeknoten = $this->pdo->fetch($this->pdo->prepare('SELECT lft, rgt, ROUND((rgt - lft - 1) / 2) AS children, ebene FROM '.$this->table.' WHERE '.$this->namefield.' = ?', array($knoten)));
        if (!$verschiebeknoten) {
            return false;
        }

        if ($toknotendata != '0') {
            $toknoten = $this->pdo->fetch($this->pdo->prepare('SELECT lft, rgt, ROUND((rgt - lft - 1) / 2) AS children, ebene FROM '.$this->table.' WHERE '.$this->namefield.' = ?', array($toknotendata)));
            if (!$toknoten) {
                return false;
            }
            // Art der Verschiebung herausfinden
            if ($verschiebeknoten['lft'] > $toknoten['lft'] && $verschiebeknoten['rgt'] < $toknoten['rgt']) {
                // Knoten wird in einen Elternknoten verschoben
                $this->pdo->prepare('UPDATE '.$this->table.' SET lft = '.$toknoten['rgt'].' - (('.$verschiebeknoten['children'].' + 1)*2), rgt = '.$toknoten['rgt'].' - 1, updated = 1, ebene = '.($toknoten['ebene'] + 1).', parent = '.$toknotendata.' WHERE '.$this->namefield.' = ?', array($knoten));

                $this->pdo->query('UPDATE '.$this->table.' SET lft = lft + ('.$toknoten['rgt'].' - '.$verschiebeknoten['rgt'].' - 1), rgt = rgt + ('.$toknoten['rgt'].' - '.$verschiebeknoten['rgt'].' - 1), updated = 1, ebene = ('.$toknoten['ebene'].' + ebene - '.$verschiebeknoten['ebene'].')+1 WHERE lft > '.$verschiebeknoten['lft'].' AND rgt < '.$verschiebeknoten['rgt'].' AND updated != 1');

                $this->pdo->query('UPDATE '.$this->table.' SET rgt = rgt - (('.$verschiebeknoten['children'].' + 1)*2), updated = 1 WHERE lft < '.$verschiebeknoten['lft'].' AND lft > '.$toknoten['lft'].' AND rgt > '.$verschiebeknoten['lft'].' AND updated != 1');
                $this->pdo->query('UPDATE '.$this->table.' SET lft = lft - (('.$verschiebeknoten['children'].' + 1)*2), rgt = rgt - (('.$verschiebeknoten['children'].' + 1)*2), updated = 1 WHERE lft > '.$verschiebeknoten['rgt'].' AND rgt < '.$toknoten['rgt'].' AND updated != 1');
            } elseif ($verschiebeknoten['lft'] > $toknoten['lft'] && $verschiebeknoten['rgt'] > $toknoten['rgt']) {
                // Container wird unter einen links liegenden Container verschoben
                $this->pdo->prepare('UPDATE '.$this->table.' SET rgt = rgt + (('.$verschiebeknoten['children'].' + 1 )*2), updated = 1 WHERE '.$this->namefield.' = ?', array($toknotendata));
                $this->pdo->prepare('UPDATE '.$this->table.' SET lft = '.$toknoten['rgt'].', rgt = ('.$toknoten['rgt'].' - 1 + (('.$verschiebeknoten['children'].' + 1)*2)), parent = '.$toknotendata.', updated = 1, ebene = '.($toknoten['ebene'] + 1).' WHERE '.$this->namefield.' = ?', array($knoten));
                $this->pdo->query('UPDATE '.$this->table.' SET lft = lft - ('.$verschiebeknoten['lft'].' - '.$toknoten['rgt'].'), rgt = rgt - ('.$verschiebeknoten['lft'].' - '.$toknoten['rgt'].'), updated = 1, ebene = ('.$toknoten['ebene'].' + ebene - '.$verschiebeknoten['ebene'].'+1) WHERE lft > '.$verschiebeknoten['lft'].' AND rgt < '.$verschiebeknoten['rgt'].' AND updated != 1');
                $this->pdo->query('UPDATE '.$this->table.' SET lft = lft + (('.$verschiebeknoten['children'].' + 1)*2), rgt = rgt + (('.$verschiebeknoten['children'].' + 1 )*2), updated = 1 WHERE lft > '.$toknoten['rgt'].' AND rgt < '.$verschiebeknoten['lft'].' AND updated != 1');
                $this->pdo->query('UPDATE '.$this->table.' SET rgt = rgt + (('.$verschiebeknoten['children'].' + 1)*2), updated = 1 WHERE lft < '.$toknoten['lft'].' AND rgt > '.$toknoten['rgt'].' AND rgt < '.$verschiebeknoten['lft'].' AND updated != 1');
                $this->pdo->query('UPDATE '.$this->table.' SET lft = lft + (('.$verschiebeknoten['children'].' + 1)*2), updated = 1 WHERE lft > '.$toknoten['rgt'].' AND lft < '.$verschiebeknoten['lft'].' AND rgt > '.$verschiebeknoten['rgt'].' AND updated != 1');
            } elseif ($verschiebeknoten['lft'] < $toknoten['lft'] && $verschiebeknoten['rgt'] < $toknoten['rgt']) {
                // Container wird unter einen rechts liegenden Container verschoben
                $this->pdo->prepare('UPDATE '.$this->table.' SET lft = lft - (('.$verschiebeknoten['children'].' + 1)*2), updated = 1 WHERE '.$this->namefield.' = ?', array($toknotendata));
                $this->pdo->prepare('UPDATE '.$this->table.' SET lft =  '.$toknoten['rgt'].' - (('.$verschiebeknoten['children'].' + 1)*2), rgt =  '.$toknoten['rgt'].' - 1, parent = '.$toknotendata.', updated = 1, ebene = '.($toknoten['ebene'] + 1).' WHERE '.$this->namefield.' = ?', array($knoten));
                $this->pdo->query('UPDATE '.$this->table.' SET lft = lft + (('.$toknoten['rgt'].' - 1) - '.$verschiebeknoten['rgt'].'), rgt = rgt + (('.$toknoten['rgt'].' - 1) - '.$verschiebeknoten['rgt'].'), updated = 1, ebene = ('.$toknoten['ebene'].' + ebene - '.$verschiebeknoten['ebene'].')+1 WHERE lft > '.$verschiebeknoten['lft'].' AND rgt < '.$verschiebeknoten['rgt'].' AND updated != 1');
                $this->pdo->query('UPDATE '.$this->table.' SET rgt = rgt - (('.$verschiebeknoten['children'].' + 1)*2), updated = 1 WHERE lft < '.$verschiebeknoten['lft'].' AND rgt > '.$verschiebeknoten['rgt'].' AND rgt < '.$toknoten['lft'].' AND updated != 1');
                $this->pdo->query('UPDATE '.$this->table.' SET lft = lft - (('.$verschiebeknoten['children'].' + 1 )*2), rgt = rgt - (('.$verschiebeknoten['children'].' + 1)*2), updated = 1 WHERE lft > '.$verschiebeknoten['rgt'].' AND rgt < '.$toknoten['rgt'].' AND updated != 1');
                $this->pdo->query('UPDATE '.$this->table.' SET lft = lft - (('.$verschiebeknoten['children'].' + 1)*2), updated = 1 WHERE lft > '.$verschiebeknoten['rgt'].' AND lft < '.$toknoten['rgt'].' AND rgt > '.$toknoten['rgt'].' AND updated != 1');
            }
            $this->pdo->query('UPDATE '.$this->table.' SET updated = 0');
        } else {
            $lastwurzel = $this->pdo->fetch($this->pdo->query('SELECT rgt FROM '.$this->table.' ORDER BY rgt DESC LIMIT 1'));
            $lastwurzel['rgt'] = $lastwurzel['rgt'] - ($verschiebeknoten['rgt'] - $verschiebeknoten['lft'] + 1);
            $this->pdo->query('UPDATE '.$this->table.' SET parent=0 WHERE lft = '.$verschiebeknoten['lft']);
            $this->pdo->query('UPDATE '.$this->table.' SET lft=lft-'.($verschiebeknoten['rgt'] - $verschiebeknoten['lft'] + 1).', updated=1 WHERE lft > '.$verschiebeknoten['rgt']);
            $this->pdo->query('UPDATE '.$this->table.' SET rgt=rgt-'.($verschiebeknoten['rgt'] - $verschiebeknoten['lft'] + 1).', updated=1 WHERE rgt > '.$verschiebeknoten['rgt']);
            $this->pdo->query('UPDATE '.$this->table.' SET lft=lft-'.$verschiebeknoten['lft'].'+'.$lastwurzel['rgt'].'+1, rgt=rgt-'.$verschiebeknoten['lft'].'+'.$lastwurzel['rgt'].'+1, ebene=ebene-'.$verschiebeknoten['ebene'].' WHERE updated=0 AND lft BETWEEN '.$verschiebeknoten['lft'].' AND '.$verschiebeknoten['rgt']);
            $this->pdo->query('UPDATE '.$this->table.' SET updated = 0');
        }
        $this->pdo->query('UNLOCK TABLES');
    }
Sowas?:ugly:
Ist meine Implementation mit PDO (war noch ohne ZF ;)), Variablen ersetzen nicht vergessen:biggrin:
Erfordert aber ein paar zusätzliche Daten.
 
yihaa! danke schonmal! ich schaus mir mal genauer an! hocke jetzt schon seit knappen 2 stunde rum und berechne lft und rgt werte für verschiedene konstellationen.. is nen ziemlicher mindfuck und bei jeder konstellation, die man durchrechnet wird die liste mit bedingungen, die man beachten muss, größer :D

sobald ich fertig bin werde ich meine (wahrscheinlich stümperhafte) implementation im zend thread posten.. vielleicht freut sich ja jemand drüber.. aber das gehört hier eigentlich nich rein ;)
 
du kannst dich ja noch von DB_NestedSet inspirieren lassen und als kleine Lib auf github packen ;)

das pear paket hab ich mir auch schon angeschaut (ist die einzige mir bekannte vernünftige library mit ordentlichem funktionsumfang).. das war mir allerdings nen wenig zu komplex, da ich eigentlich nur die nötigen operationen "ablesen" wollte.. jetzt im nachhinein wäre es vielleicht sinnvoller gewesen, sich das genauer anzuschauen..

Eine gute NestedSet-Library fehlt nämlich noch immer.

eine nestedset library wird es.. über das "gut" dürft dann ihr entscheiden.. ich hab da aber schon ne ahnung, in welche richtung die meinung gehen wird.. :ugly: