邻接表模式有两个表格
-
22-09-2019 - |
题
所以我 想想 我的问题归结为两个问题:
我怎么建立一个可穿越树形结构PHP当树存在MySQL(两个表之间)使用相邻清单模型方法,同时保持性能在想什么呢?
什么是可维护的方式来显示的树在所需要的格式,无需重复历码和乱丢垃圾的逻辑,如果/else和开声明?
下面是更多的细节:
我使用的Zend框架。
我正与一个调查问卷。其存储在一个数据库之间的两个单独的表格:问题和question_groups.每个表格延伸适当的Zend_Db_Table_*班。层次的代表是利用相邻清单模型的方法。
我意识到该问题,我运行为都可能由于这样的事实,我的馅树形结构成一个数据库所以我开到的替代品。然而,我还储存调查表的答复者和他们的反应以备选办法将需要支持。
调查表需求显示在各种HTML格式:
- 作为一形式输入的响应(使用改变)
- 作为一个序列表(嵌套的)问题(和 一些 团)的链接查看的反应的问题,或通过组。
- 作为一个序列表(嵌套的)的答复所附的每个问题。
问题是叶节点和question_groups可以包含其他question_groups和/或问题。合并,有一点超过100行处理和显示器。
目前,我有一个帮手会所有处理使用递归来检索question_group的儿童(查询其执行之间的联盟的两个表格:QuestionGroup::getChildren($id))。再加上时,显示问卷与问题的响应另外两个查询需要检索的答复和应对每个问题。
同时,该网页载的时间不很长,这种方法的感觉是错误的。递归加多个数据库查询的几乎每一个节点没让我觉得很温暖的和模糊的内部。
我已经试过了 递归-不 和回归方法对充分树列返回自联盟建立一个分层列遍并显示。然而,这似乎打破,因为有重复的节点id由于事实上团体和个问题是储存在单独的表格。也许我失去了一些东西没有...
目前,逻辑显示树在格式上面列出的是一个相当的混乱。我不想重复历逻辑所有的地方。然而,条件,所有的地方不会产生最易于维护的代码。我已经读了关于访客、装修和一些PHP SPL迭代,但我仍然感觉还不清楚如何将所有的工作,同类延伸Zend_Db_Table,Zend_Db_Table_Rowset和Zend_Db_Table_Row.特别是因为我还没有解决前面的问题的建筑物的层次结构的数据库。这将是很好的增添新的显示格式(或修改现有的)较容易。
解决方案
邻接表传统上给你一个
parent_id
列在每个行链接的行其直接的父母。的parent_id
是空的,如果该行为根的一棵树。但是这导致你到运行许多SQL查询,这是昂贵的。添加另一列
root_id
因此每个行知道是什么树属。这样,你可以获取的所有节点的一个给定的树有一个单一的SQL query.添加一个方法你Table
类,以获取Rowset
通过树根id。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; } }
写一个自定义类的延伸
Zend_Db_Table_Row
写功能检索所给予行的父也是一个Rowset
其儿童。的Row
类应包含保护数据的对象,参考家长和该阵列的儿童。一个Row
对象可以还有一个getLevel()
功能和一个getAncestorsRowset()
功能用面包屑。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() {} }
写一个自定义类的延伸
Zend_Db_Table_Rowset
有一个功能,以迭代行行集中,设置父母和儿童参考文献以便可以随后横他们作为一棵树。还的Rowset
应该有一个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; } } } }
现在你可以打电话 getRootRow()
在行集和返回的根本节点。一旦你已经根节点,你可以打电话 getChildren()
环。然后你可以打电话 getChildren()
还可对任何这些儿童中间,并递归的输出一种树在任何格式要你想。