Frage

Also ich denkt mein Problem läuft darauf hinaus, zwei Fragen nach unten:

  1. Wie erstelle ich eine verfahrbaren Baumstruktur in PHP, wenn der Baum in MySQL gespeichert (zwischen zwei Tabellen), um den Adjazenzliste Modell-Ansatz, während der Leistung unter Berücksichtigung?

  2. Was ist ein wartbar Ansatz, den Baum in die benötigten Formate zur Anzeige ohne Traversal Code zu duplizieren und Littering die Logik mit if / else und switch-Anweisungen?

Im Folgenden sind weitere Details:

Ich bin mit dem Zend Framework.

Ich arbeite mit einem Fragebogen. Fragen und question_groups: Es ist in einer MySQL-Datenbank zwischen zwei separaten Tabellen gespeichert. Jeder Tisch erstreckt sich die entsprechenden Zend_Db_Table_ * Klassen. Die Hierarchie wird repräsentiert den Adjazenzliste Modell-Ansatz.

erkenne ich die Probleme, die ich in renne werden wahrscheinlich aufgrund der Tatsache, dass ich eine Baumstruktur in einem RDBMS bin Füllung so ich Alternativen offen bin. Allerdings bin ich Speicherung auch Fragebogen Befragten und ihre Antworten so alternative Ansätze brauchen würde, dass unterstützen.

Die Fragebogen Bedürfnisse in verschiedenen HTML-Format angezeigt werden:

  1. Als eine Form für die Eingabe von Antworten (mit Zend_Form)
  2. Als eine geordnete Liste (verschachtelt) mit Fragen (und einige Gruppen) als Links zu Sicht Antworten für Frage oder Gruppe.
  3. Als eine geordnete Liste (verschachtelt) mit Antworten auf jede Frage angehängt.

Fragen sind Blattknoten und question_groups können andere question_groups und / oder Fragen enthalten. In Kombination gibt es ein wenig mehr als 100 Zeilen zu verarbeiten und anzuzeigen.

Derzeit habe ich einen View Helfer, die alle funktioniert die Verarbeitung Rekursion unter Verwendung eines question_group Kinder abzurufen (eine Abfrage, die eine Verbindung zwischen den beiden Tabellen führt: QuestionGroup :: getChildren ($ id)). Plus, wenn Fragebogen mit der Frage-Antwort zwei weitere Anfragen Anzeigen benötigt, um den Befragten und ihre Antwort auf jede Frage abgerufen werden.

Während der Ladezeit ist nicht sehr lange dieser Ansatz fühlt sich falsch an. Rekursion und mehrere Datenbankabfragen für fast jeden Knoten mich nicht machen fühle mich sehr warm und flockig innen.

Ich habe versucht, Rekursion -Weniger und rekursive Methoden, die auf dem vollen Baum-Array aus der Union zurück eine hierarchische Anordnung zu durchlaufen und die Anzeige aufzubauen. Doch das scheint da zu brechen ist duplizierten Knoten-IDs aufgrund der Tatsache, dass Gruppen und Fragen in separaten Tabellen gespeichert sind. Vielleicht bin ich etwas fehlt es ...

Derzeit ist die Logik, den Baum in den oben angegebenen Formaten anzuzeigen ist eine ziemliche Sauerei. Ich würde es vorziehen, nicht die Traversal Logik ganz über den Platz zu duplizieren. Allerdings conditionals ganzen Ort produzieren nicht die am einfachsten wartbaren Code entweder. Ich habe auf Besucher nachlesen, Dekorateure und einige des SPL Iteratoren PHP, aber ich fühle mich immer noch unklar, wie das würde alle arbeiten zusammen mit den Klassen, die Zend_Db_Table, Zend_Db_Table_Rowset und Zend_Db_Table_Row erweitern. Vor allem, da ich das bisherige Problem des Aufbaus die Hierarchie aus der Datenbank nicht gelöst haben. Es wäre schön, neue Anzeigeformate hinzuzufügen (oder vorhandene ändern) etwas leicht.

War es hilfreich?

Lösung

  • Die Adjazenzliste gibt Ihnen traditionell eine parent_id Spalte in jeder Zeile, die eine Zeile zu seinen unmittelbar Eltern verbindet. Die parent_id ist NULL, wenn die Zeile die Wurzel eines Baums ist. Aber das führt Sie viele SQL-Abfragen ausführen, was teuer ist.

  • Fügen Sie eine weitere Spalte root_id so jede Zeile weiß, was Baum es gehört. Auf diese Weise können Sie alle Knoten eines bestimmten Baumes mit einer einzigen SQL-Abfrage holen. Fügen Sie eine Methode, um Ihre Table Klasse eine Rowset von der Baumwurzel-ID zu holen.

    class QuestionGroups extends Zend_Db_Table_Abstract
    {
        protected $_rowClass = 'QuestionGroup';
        protected $_rowsetClass = 'QuestionGroupSet';
        protected function fetchTreeByRootId($root_id)
        {
             $rowset = $this->fetchAll($this
                ->select()
                ->where('root_id = ?', $root_id)
                ->order('id');
            );
            $rowset->initTree();
            return $rowset;
        }
    }
    
  • Schreiben Sie eine benutzerdefinierte Klasse Zend_Db_Table_Row und Schreibfunktionen zur Verlängerung der gegebenen Zeile des Mutter abrufen und auch eine Rowset seiner Kinder. Die Row Klasse sollte geschützte Daten enthalten Objekte, die Eltern und das Array von Kindern zu verweisen. Ein Row Objekt kann auch eine getLevel() Funktion und eine getAncestorsRowset() Funktion für Paniermehl.

    class QuestionGroup extends Zend_Db_Table_Row_Abstract
    {
        protected $_children = array();
        protected $_parent   = null;
        protected $_level    = null;
        public function setParent(Zend_Db_Table_Row_Abstract $parent)
        {
            $this->_parent = $parent;
        }
        public function getParent()
        {
            return $this->_parent;
        }
        public function addChild(Zend_Db_Table_Row_Abstract $child)
        {
            $this->_children[] = $child;
        }
        public function getChildren()
        {
            return $this->_children;
        }
        public function getLevel() {}
        public function getAncestors() {}
    }
    
  • Schreiben Sie eine benutzerdefinierte Klasse erweitern Zend_Db_Table_Rowset, die eine Funktion zu iterieren über die Zeilen im Rowset hat, das Setzen von Eltern und Kindern Referenzen, so dass Sie sie anschließend als ein Baum durchqueren können. Auch die Rowset sollte eine getRootRow() Funktion hat.

    class QuestionGroupSet extends Zend_Db_Table_Rowset_Abstract
    {
        protected $_root = null;
        protected function getRootRow()
        {
            return $this->_root;
        }
        public function initTree()
        {
            $rows = array();
            $children = array();
            foreach ($this as $row) {
              $rows[$row->id] = $row;
              if ($row->parent_id) {
                $row->setParent($rows[$row->parent_id]);
                $rows[$row->parent_id]->addChild($row);
              } else {
                $this->_root = $row;
              }
            }
        }
    }
    

Jetzt können Sie getRootRow() auf einem rowset nennen, und es gibt den Wurzelknoten. Sobald Sie den Wurzelknoten haben, können Sie getChildren() und Schleife über sie nennen. Dann können Sie rufen getChildren() auch auf jeder dieser Zwischen Kinder und rekursiv Ausgabe einen Baum in einem beliebigen Format Sie wollen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top