Pregunta

Así que pensar mi problema se reduce a dos preguntas:

  1. ¿Cómo construir una estructura de árbol desplazable en PHP cuando el árbol se almacena en MySQL (entre dos tablas) utilizando el enfoque de lista de adyacencia modelo mientras se mantiene el rendimiento en mente?

  2. ¿Qué es un enfoque de mantener a mostrar el árbol en los formatos necesarios sin duplicar código de recorrido y tirar basura con la lógica if / else y switch?

A continuación se presentan más detalles:

Estoy usando el Zend Framework.

Estoy trabajando con un cuestionario. Se almacena en una base de datos MySQL entre dos mesas separadas: preguntas y question_groups. Cada tabla amplía las apropiadas Zend_Db_Table_ * clases. La jerarquía se representa usando el enfoque de lista de adyacencia modelo.

Soy consciente de los problemas que estoy corriendo en son probablemente debido al hecho de que estoy relleno de una estructura de árbol en un RDBMS, así que estoy abierto a otras alternativas. Sin embargo, también estoy almacenar las respuestas al cuestionario y sus respuestas hasta enfoques alternativos tendrían que soportar eso.

Las necesidades del cuestionario que se mostrará en varios formatos HTML:

  1. Como una forma para introducir las respuestas (usando Zend_Form)
  2. Como una lista ordenada (anidada) con preguntas (y algunos grupos) como enlaces para ver las respuestas de pregunta o de grupo.
  3. como una lista ordenada (anidada) con respuestas adjuntas a cada pregunta.

Las preguntas son nodos hoja y question_groups pueden contener otros question_groups y / o preguntas. En conjunto, hay un poco más de 100 filas para procesar y mostrar.

Actualmente, tengo un ayudante de vista que hace todo el procesamiento utilizando la recursividad para recuperar los hijos de un question_group (una consulta que realiza una unión entre las dos tablas: QuestionGroup :: getChildren ($ id)). Además, cuando se presentan cuestionario con la respuesta de la pregunta se necesitan otros dos consultas adicionales para recuperar el demandado y su respuesta a cada pregunta.

No Mientras que el tiempo de carga de la página es muy larga este enfoque se siente mal. Recursividad además varias consultas de bases de datos para casi todos los nodos no me hacen sentir muy cálido y difuso en el interior.

He intentado recursividad -menos y métodos recursivos en la matriz árbol lleno de regresar de la Unión de formar una matriz jerárquica para atravesar y la pantalla. Sin embargo, parece que a descomponer ya que no se duplican los identificadores de nodo debido al hecho de que los grupos y las preguntas se almacenan en tablas separadas. Tal vez me falta algo allí ...

En la actualidad, la lógica para visualizar el árbol en los formatos mencionados anteriormente es un buen lío. Prefiero no duplicar la lógica de recorrido por todo el lugar. Sin embargo, los condicionales por todo el lugar no producen el código más fácil de mantener, ya sea. He leído en los visitantes, decoradores y algunos de los iteradores PHP SPL pero todavía me siento confuso en cuanto a la forma en que lo haría todo el trabajo junto con las clases que están ampliando Zend_Db_Table, Zend_Db_Table_Rowset y Zend_Db_Table_Row. Sobre todo porque no he resuelto el problema anterior de la construcción de la jerarquía de la base de datos. Sería bueno para añadir nuevos formatos de presentación (o modificar los existentes) algo fácil.

¿Fue útil?

Solución

  • La lista de adyacencia tradicionalmente le da una columna parent_id en cada fila que une una fila a su padre inmediato. El parent_id es NULL si la fila es la raíz de un árbol. Pero esto lleva a que corren muchas consultas SQL, que es caro.

  • Añadir otra root_id columna para cada fila sabe qué árbol pertenece. De esa manera se puede recuperar todos los nodos de un árbol dado con una sola consulta SQL. Agregue un método a la clase Table a buscar una Rowset por id de la raíz del árbol.

    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;
        }
    }
    
  • Escribir una clase personalizada ampliar las funciones Zend_Db_Table_Row y escritura para recuperar los padres de la fila dada y también un Rowset de sus hijos. La clase Row debe contener los datos protegidos objetos para hacer referencia a que el padre y la matriz de los niños. Un objeto Row también puede tener una función getLevel() y una función getAncestorsRowset() para pan rallado.

    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() {}
    }
    
  • Escribir un Zend_Db_Table_Rowset extendiéndose clase personalizada que tiene una función para repetir las filas del conjunto de filas, el establecimiento de los padres y niños Referencias para que posteriormente puede recorrer como un árbol. También el Rowset debe tener una función getRootRow().

    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;
              }
            }
        }
    }
    

Ahora usted puede llamar getRootRow() en un conjunto de filas, y se devuelve el nodo raíz. Una vez que tenga el nodo raíz, puede llamar getChildren() y lazo sobre ellos. A continuación, puede llamar getChildren() también en cualquiera de estos niños intermedios y de salida de forma recursiva un árbol en cualquier formato que desee.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top