GORM - Nested Sets

Dieser Bereich dient dazu, neue Features zu diskutieren und für die Entwicklung zu dokumentieren. // This area is dedicated to new features including proposals and documentation.
Gesperrt
TipTop
Beiträge: 193
Registriert: 25.08.2011, 22:37:08
Wohnort: Klagenfurt, Österreich
Kontaktdaten:

GORM - Nested Sets

Beitrag von TipTop » 23.10.2012, 17:55:03

Ich habe vor 'ner Weile mit einer Nested Sets Implementierung begonnen und diese ist nun auch fertig - ich dachte ich frage jetzt mal nach ob Ihr für diese Verwendung finden könntet. Dann könnten wir ja darüber nachdenken ob man diese in den GORM integrieren kann. Die Abfragen sind performanter als die bisherige Tree-Implementierung, welche eine eigene cmp_*-Tabelle verwendet.

Die API sieht folgend aus:
  • addRootNode(TreeNode $node)
  • addNode(TreeNode $node, TreeNode $parentNode)
  • loadRootNodeByCriterion($objectName, GenericCriterionObject $criterion)
  • loadTree(TreeNode $rootNode, GenericCriterionObject $criterion = null, $endLevel = -1) (1)
  • loadTreeByTextStatement(TreeNode $rootNode, $statement)
  • getPath(TreeNode $node)
  • moveByReference(TreeNode $node, TreeNode $reference, $position = 'after') (2)
  • moveLeft(TreeNode $node)
  • moveRight(TreeNode $node)
  • deleteNode(TreeNode $node, $deleteChildren = true) (3)
(1) - $endLevel mit dem default Wert -1 bedeutet, dass der komplette Baum ab $rootNode geladen wird. Der Wert 0 würde nur direkte Child-Nodes von $rootNode laden
(2) - $node wird bei $position = after nach $reference, bei $position = before vor $reference verschoben
(3) - Ist $deleteChildren auf false gesetzt, werden die Child-Nodes des zu löschenden Tree-Node auf dessen Ebene verschoben


Dachte daran die Methoden in einer Klasse GenericTree unterzubringen, welche von GenericORRelationMapper erbt & eine Klasse GenericTreeNode die als Basisklasse GenericDomainObject verwendet. Aber die Frage ist halt, ob so eine Erweiterung überhaupt zum GORM passen würde?

Megger
Beiträge: 1233
Registriert: 04.11.2008, 10:57:37

Re: GORM - Nested Sets

Beitrag von Megger » 23.10.2012, 18:11:23

Klingt auf jeden Fall interessant, hätte da allerdings noch ne Frage
(1) - $endLevel mit dem default Wert -1 bedeutet, dass der komplette Baum ab $rootNode geladen wird. Der Wert 0 würde nur direkte Child-Nodes von $rootNode laden
Meiner Meinung nach würde ich erwarten bei dem Wert 1 die direkten Child Nodes zu bekommen, bei 0 bekomme ich halt keine Child Nodes sondern nur das rootNode, oder hat das programmiertechnische Gründe?
Tutorial: Browsergame mit dem APF (Die ersten Parts handeln von Installation und Inbetriebnahme des APFs, deswegen sicherlich auch für alle Nicht-Browsergame-Programmierer interessant)

APF-Version
  • Entwicklung: 2.0
  • Produktiv: 1.15

Benutzeravatar
jwlighting
Beiträge: 466
Registriert: 14.07.2010, 14:23:58
Wohnort: LK Oldenburg
Kontaktdaten:

Re: GORM - Nested Sets

Beitrag von jwlighting » 23.10.2012, 18:45:17

Hallo Nico,

wie du schon weißt, besteht bei mir auf jeden Fall sehr großes Interesse an einer NestedSets Implementierung. Für den GORM und das APF wäre das auf alle Fälle ein großer Mehrwert, denn Baumstrukturen in Datenbanken performant zu speichern ist immer wieder ein lästiges Thema, auf das man auch recht häufig stößt.
(2) - $node wird bei $position = after nach $reference, bei $position = before vor $reference verschoben
Du solltest vielleicht nicht direkt mit den Strings arbeiten, sondern diese in Konstanten ablegen. Ich weiß jetzt nicht wie deine Klasse heißt, aber du kannst dann über bspw. NestedSets::INSERT_AFTER bzw. self::INSERT_AFTER diesen String referenzieren - und diese Konstanten werden von einer IDE auch automatisch erkannt und vorgeschlagen.

Deklarieren tust du sie so:

Code: Alles auswählen

class NestedSets ... {

   const INSERT_AFTER = 'after';

   const INSERT_BEFORE = 'before';

   ...

}
 

LG :)
Jan

PS: Magst du (bei eigenem Interesse) einen neuen Mapper für das APFelSMS auf Basis der NestedSets Implementierung anbieten?

Menschen irren - Politiker sind Menschen.
Für den Norddeutschen ist 1kW = 2 Pfund Schlick.

TipTop
Beiträge: 193
Registriert: 25.08.2011, 22:37:08
Wohnort: Klagenfurt, Österreich
Kontaktdaten:

Re: GORM - Nested Sets

Beitrag von TipTop » 23.10.2012, 21:38:18

Megger hat geschrieben:
(1) - $endLevel mit dem default Wert -1 bedeutet, dass der komplette Baum ab $rootNode geladen wird. Der Wert 0 würde nur direkte Child-Nodes von $rootNode laden
Meiner Meinung nach würde ich erwarten bei dem Wert 1 die direkten Child Nodes zu bekommen, bei 0 bekomme ich halt keine Child Nodes sondern nur das rootNode, oder hat das programmiertechnische Gründe?
Ja stimmt, das macht wenig Sinn :oops: Habs nun so wie von dir beschrieben geändert.
jwlighting hat geschrieben: Du solltest vielleicht nicht direkt mit den Strings arbeiten, sondern diese in Konstanten ablegen.
Kann man Klassenkonstanten auch in der Methoden-Signatur verwenden (also als Default-Wert für Parameter)?

jwlighting hat geschrieben: PS: Magst du (bei eigenem Interesse) einen neuen Mapper für das APFelSMS auf Basis der NestedSets Implementierung anbieten?
Gerne - müsstest mir aber paar Einweisungen geben. Falls Du bei Skype registriert bist, füge mich mal bitte hinzu: nicolas_pecher

Benutzeravatar
jwlighting
Beiträge: 466
Registriert: 14.07.2010, 14:23:58
Wohnort: LK Oldenburg
Kontaktdaten:

Re: GORM - Nested Sets

Beitrag von jwlighting » 24.10.2012, 22:16:47

Kann man Klassenkonstanten auch in der Methoden-Signatur verwenden (also als Default-Wert für Parameter)?
Natürlich!! Schau dir mal APFService an, dort kannst du dir das abgucken.
Innerhalb der Klasse immer self::KONSTANTE, sonst KlassenName::KONSTANTE verwenden.
Gerne - müsstest mir aber paar Einweisungen geben. Falls Du bei Skype registriert bist, füge mich mal bitte hinzu: nicolas_pecher
Das mache ich doch gerne. Leider aber erst ab dem 5.11., davor habe ich keine Zeit.
Du kannst aber schon mal hier schauen: http://wiki.adventure-php-framework.org ... r_auslesen , daraus ist ein wenig mein Mapping-Konzept ersichtlich.
Ansonsten brauchst du eigentlich nur das Interface SMSMapper zu implementieren. Wie aus Dekoratoren und Page das dekorierte Objekt gebaut wird, siehst du wenn du dir die getPage() und getPageDec()-Methoden in SMSManager anguckst und mit den entsprechenden Methoden in SMSXMLMapper vergleichst - nur falls es dir unter den Nägeln brennt, schon an zu fangen.

Wie das APFelSMS und seine Komponenten zusammenspielen, steht auch in der Doku im wiki.

LG :)
Jan

Menschen irren - Politiker sind Menschen.
Für den Norddeutschen ist 1kW = 2 Pfund Schlick.

Megger
Beiträge: 1233
Registriert: 04.11.2008, 10:57:37

Re: GORM - Nested Sets

Beitrag von Megger » 25.10.2012, 23:25:03

Soll die API nur für den GORM sein? Ich hätte nämlich durchaus Anwendungsmöglichkeiten außerhalb des GORMs! Konkret geht es um einen Oxid Shop, den ich dann mit einem dbDriver ansprechen würde
Tutorial: Browsergame mit dem APF (Die ersten Parts handeln von Installation und Inbetriebnahme des APFs, deswegen sicherlich auch für alle Nicht-Browsergame-Programmierer interessant)

APF-Version
  • Entwicklung: 2.0
  • Produktiv: 1.15

TipTop
Beiträge: 193
Registriert: 25.08.2011, 22:37:08
Wohnort: Klagenfurt, Österreich
Kontaktdaten:

Re: GORM - Nested Sets

Beitrag von TipTop » 26.10.2012, 11:44:33

Megger hat geschrieben:Soll die API nur für den GORM sein?
Naja derzeit nutze ich manchmal GenericORRelationMapper-Methoden, oft aber auch executeTextStatement() vom DBDriver, weil ich manchmal SQL-Statements ausführen muss, die per GORM nicht möglich werden. Bsp:

Code: Alles auswählen

    public function deleteNode(TreeNode $node, $deleteChildren = true) {
    
        $dbDriver = $this->getORMapper()->getDbDriver();
        $tableName = $this->getTableNameByTreeNode($node);
        $lft = $node->getLft();
        $rgt = $node->getRgt();
        $level = $node->getLevel();
      
        // The child nodes of this node should not be deleted so they 
        // have to be moved at the level of their parent's node.
        if ($deleteChildren === false) { 
            
            // delete node   
            $sqlStmt = 'DELETE FROM ' . $tableName . ' WHERE Lft = ' . $lft;
            $dbDriver->executeTextStatement($sqlStmt);
            
            // update lft, rgt and level values of the child nodes
            $sqlStmt = 'UPDATE ' . $tableName . ' SET '
                     . 'Lft = Lft - 1, Rgt = Rgt - 1, Level = ' . $level . ' '
                     . 'WHERE Lft BETWEEN ' . $lft . ' AND ' . $rgt;
            $dbDriver->executeTextStatement($sqlStmt);
            
            // update lft values of the nodes around the deleted node
            $sqlStmt = 'UPDATE ' . $tableName . ' SET Lft = Lft - 2 WHERE Lft > ' . $lft;
            $dbDriver->executeTextStatement($sqlStmt);
            
            // update rgt values of the nodes around the deleted node
            $sqlStmt = 'UPDATE ' . $tableName . ' SET Rgt = Rgt - 2 WHERE Rgt > ' . $rgt;
            $dbDriver->executeTextStatement($sqlStmt);
            
            return true;            
            
        }
                      
        // delete node including child nodes.
        $sqlStmt = 'DELETE FROM ' . $tableName . ' '
                 . 'WHERE Lft BETWEEN ' . $lft . ' AND ' . $rgt;                        
        $dbDriver->executeTextStatement($sqlStmt);
        
        // update lft values to close the hole in the tree
        $sqlStmt = 'UPDATE ' . $tableName . ' SET Lft = Lft - ' . ($rgt - $lft + 1) . ' '
                 . 'WHERE Lft > ' . $rgt;
        $dbDriver->executeTextStatement($sqlStmt);
        
        // update rgt values  to close the hole in the tree
        $sqlStmt = 'UPDATE ' . $tableName . ' SET Rgt = Rgt - ' . ($rgt - $lft + 1) . ' '
                 . 'WHERE Rgt > ' . $rgt;
        $dbDriver->executeTextStatement($sqlStmt);
        
        return true;
        
    }  
In anderen Methoden kommt aber auch nur der GORM zum Einsatz - ist derzeit ein bissl ein wirrwarr.
Wir wär es wenn wir den GORM komplett von der Nested Sets Implementierung abkoppeln und stattdessen in die Klasse TreeManager (beinhaltet derzeit die Methoden zur Modifizierung des Baumes) ein Repository injizieren - standardmäßig könnte das APF dann 2 Repositories mitliefern, eines verwendet für die Datenverwaltung den GORM, das andere verwendet nur einen db-driver. Der TreeManager baut seine SQL-Statements aus PHP-Objekten auf, diese übergibt er dem Repository und das Repository erledigt dann den Rest. Dann wäre eine (komplette) SQL-Abstrahierung notwendig, was aber für core::database eh eine Bereicherung wäre. Die SQL-Abstrahierung könnte man zudem später ja auch noch im GORM integrieren.

Megger
Beiträge: 1233
Registriert: 04.11.2008, 10:57:37

Re: GORM - Nested Sets

Beitrag von Megger » 26.10.2012, 13:52:28

Es war sowieso mal angedacht den GORM so umzuschreiben, sodass dieser mit jedem beliebigen Datenbanksystem arbeiten kann und nicht nur mit MySQL, dadurch wären dann auch Anwendungen mit SQLite in Zusammenhang mit dem GORM möglich!
Vielleicht könnte man das ganze dann auf einen Schlag in 1.17 erledigen! Und die Nested Sets auch ohne GORM verfügbar zu machen hat meine voll Zustimmung :D
Tutorial: Browsergame mit dem APF (Die ersten Parts handeln von Installation und Inbetriebnahme des APFs, deswegen sicherlich auch für alle Nicht-Browsergame-Programmierer interessant)

APF-Version
  • Entwicklung: 2.0
  • Produktiv: 1.15

TipTop
Beiträge: 193
Registriert: 25.08.2011, 22:37:08
Wohnort: Klagenfurt, Österreich
Kontaktdaten:

Re: GORM - Nested Sets

Beitrag von TipTop » 29.10.2012, 12:48:10

Megger hat geschrieben:Es war sowieso mal angedacht den GORM so umzuschreiben, sodass dieser mit jedem beliebigen Datenbanksystem arbeiten kann und nicht nur mit MySQL, dadurch wären dann auch Anwendungen mit SQLite in Zusammenhang mit dem GORM möglich!
Vielleicht könnte man das ganze dann auf einen Schlag in 1.17 erledigen! Und die Nested Sets auch ohne GORM verfügbar zu machen hat meine voll Zustimmung :D
Gut, ich hab das Thema mal auf die Roadmap gesetzt. Hast Du dir zur Datenbankabstraktion schon Gedanken gemacht?

Grüße
Nico

Megger
Beiträge: 1233
Registriert: 04.11.2008, 10:57:37

Re: GORM - Nested Sets

Beitrag von Megger » 29.10.2012, 12:59:48

Ja, ich hatte mich schonmal mit dem Thema beschäftigt ... moment ... hier
Ist schon ein Weilchen her :D Aber soweit ich mich erinnere, gibt es ansich gar nicht soviele Stellen in wo der GORM Statements erzeugt. Das Erstellen der Statements muss dann ausgelagert werden, dadurch kann man dann jedes Datenbanksystem dranhängen, solange man einen passenden Mapper schreibt
Tutorial: Browsergame mit dem APF (Die ersten Parts handeln von Installation und Inbetriebnahme des APFs, deswegen sicherlich auch für alle Nicht-Browsergame-Programmierer interessant)

APF-Version
  • Entwicklung: 2.0
  • Produktiv: 1.15

TipTop
Beiträge: 193
Registriert: 25.08.2011, 22:37:08
Wohnort: Klagenfurt, Österreich
Kontaktdaten:

Re: GORM - Nested Sets

Beitrag von TipTop » 29.10.2012, 13:29:01

Megger hat geschrieben:Aber soweit ich mich erinnere, gibt es ansich gar nicht soviele Stellen in wo der GORM Statements erzeugt. Das Erstellen der Statements muss dann ausgelagert werden, dadurch kann man dann jedes Datenbanksystem dranhängen, solange man einen passenden Mapper schreibt
Bzgl. dem Auslagern von Statemens dachte ich an SQL-Objekte wie z.B.:

Code: Alles auswählen

   
public function loadObjectList($objectName) {
    $select = new Select(Select::ALL_PROPERTIES);
    $select->addFrom($this->mappingTable[$objectName]['Table']);
    $result = $this->dbDriver->executeStatement($select, $this->logStatements);
    return $this->loadObjectListByStatementResult($objectName, $result);
} 
Die Mapper würden ja nur den GORM was nützen, in Implementierungen wie Nested Sets, wo teilweise kein GORM verwendet wird, müsste dann erst ne SQL-Abstraktion her (bzw. wieder andere Mapper), damit man nicht zu einem DBMS gebunden ist.

Benutzeravatar
jwlighting
Beiträge: 466
Registriert: 14.07.2010, 14:23:58
Wohnort: LK Oldenburg
Kontaktdaten:

Re: GORM - Nested Sets

Beitrag von jwlighting » 02.11.2012, 18:15:50

Hätte da noch einen anderen Vorschlag, den icgh bei meiner damals nicht vollendeten NestetSets-Implementierung auch eingebaut hatte: Sofern man InnoDB Tabellen verwenden (bei MySQL), ist es wegen der logisch zusammenhängenden Statements sinnvoll, die Statements in Transactions zu "verpacken". Dann kann man im Falle eines Fehlers bei einer der Queries vorhergehende Queries im Rahmen der Fehlerbehandlung auch einfach rückgängig machen, und vermeidet so Datenmüll.

LG :)
Jan

PS: Siehe auch...
http://dev.mysql.com/doc/refman/5.6/en/ ... tions.html
http://dev.mysql.com/doc/refman/5.6/en/ ... tions.html

Menschen irren - Politiker sind Menschen.
Für den Norddeutschen ist 1kW = 2 Pfund Schlick.

Benutzeravatar
jwlighting
Beiträge: 466
Registriert: 14.07.2010, 14:23:58
Wohnort: LK Oldenburg
Kontaktdaten:

Re: GORM - Nested Sets

Beitrag von jwlighting » 30.03.2013, 21:00:37

Hallo Nico,

es ist ja nun schon etwas Zeit ins Land gegangen :)
Ich denke, dass Interesse an deiner Implementierung ist immer noch groß.

Magst du sie zum APF beitragen und veröffentlichen?

Wenn es dir Recht ist, können wir sie dann gerne gemeinsam weiterentwickeln.

LG :)
Jan

Menschen irren - Politiker sind Menschen.
Für den Norddeutschen ist 1kW = 2 Pfund Schlick.

Gesperrt

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 3 Gäste