2016-11-28 40 views
0

使用Codeigniter,我需要显示组织列表。有些组织会拥有子组织,并可能包含子组织的子组织,因此需要在其父级下的列表中显示,如果您愿意,可以缩进。使用Codeigniter封闭表显示分层数据

我正在使用闭合表来存储组织层次结构,这对于插入,选择子项等非常有用,但是当涉及到在单个列表/查询中选择所有组织及其子项时,我遇到了困难。

的组织表:

CREATE TABLE IF NOT EXISTS `organisations` (
    `org_id` INT NOT NULL AUTO_INCREMENT, 
    `org_name` VARCHAR(60) NOT NULL, 
    `address1` VARCHAR(40) NULL DEFAULT NULL, 
    `address2` VARCHAR(40) NULL DEFAULT NULL, 
    `address3` VARCHAR(40) NULL DEFAULT NULL, 
    `town` VARCHAR(20) NULL DEFAULT NULL, 
    `county` VARCHAR(20) NULL DEFAULT NULL, 
    `pcode` VARCHAR(10) NULL DEFAULT NULL, 
    `phone` VARCHAR(12) NULL DEFAULT NULL, 
    `support_email` VARCHAR(60) NOT NULL, 
    `active` TINYINT(4) NULL DEFAULT '1', 
    PRIMARY KEY (`organisation_id`)) 
ENGINE = InnoDB 
DEFAULT CHARACTER SET = utf8; 

而且org_hierarchy表

CREATE TABLE IF NOT EXISTS `org_hierarchy` (
    `id` INT(11) NOT NULL AUTO_INCREMENT, 
    `ancestor` INT(11) NOT NULL, 
    `descendant` INT(11) NOT NULL, 
    `lvl` INT(11) NOT NULL, 
    PRIMARY KEY (`id`)) 
ENGINE = InnoDB 
DEFAULT CHARACTER SET = utf8; 

这是我用在我的模型来查询数据库,并得到一个组织的儿童的方法:

public function get_children($org_id, $node_id = 0, $self = TRUE, $level = TRUE){ 

    $this->db->select('t.org_id,t.org_name,t.org_label'); 
    $this->db->from($this->closure_table." c1"); 
    $this->db->join($this->table.' t','t.area_id = c1.descendant'); 
    $this->db->join($this->closure_table.' c2', 'c2.lvl IN(1) AND c2.descendant = c1.descendant','LEFT'); 
    $this->db->where('c1.ancestor',$node_id); 
    $this->db->where('t.org_id',$org_id); 

    if(!$self){$this->db->where('c1.descendant <>', $node_id);} 

    if($level){$this->db->where('c1.lvl = ', $level);} 

    $query = $this->db->get(); 

    if(!$query->num_rows()){return FALSE;} 

    $result = $query->result(); 

    return $result; 
} 

但是,如何修改此查询以显示所有组织的完整列表g被上级组织牵制?

我可以通过下面的查询查询并获取单个组织及其子项,但是如何修改查询以将所有组织与子项一起获取?当然,我必须接近?

SELECT o.* FROM organisations o 
    JOIN org_hierarchy h 
     ON (o.org_id = h.descendant) 
    WHERE h.ancestor = 3 

我试过很多方法,我似乎无法改变它包括所有组织?

自卸org_hierarchy表

mysql> SELECT * FROM org_hierarchy 
    -> ; 
+----+----------+------------+-----+ 
| id | ancestor | descendant | lvl | 
+----+----------+------------+-----+ 
| 1 |  2 |   2 | 0 | 
| 2 |  3 |   3 | 0 | 
| 3 |  4 |   4 | 0 | 
| 4 |  3 |   5 | 1 | 
| 5 |  5 |   5 | 0 | 
| 7 |  3 |   6 | 2 | 
| 8 |  5 |   6 | 1 | 
| 9 |  6 |   6 | 0 | 
+----+----------+------------+-----+ 
+0

是你的表org_hierarchy刻在石头上,从浏览器中调用它呢? 因为在我看来,这个结构有点不一致 - 为什么不使用像嵌套集合模型或邻接列表这样的方法?是的,我需要这样的恐惧。我能够查询和获得一个单一的组织与子女,但我似乎无法打开它的所有组织? – sintakonte

+0

如何保存一个没有祖先但有后代的入口,反之亦然?你是否将字段保留为NULL? 以及那些不具备两者的物品呢? – sintakonte

+0

我不,他们有一个祖先和后代存储。如果它的顶级,后代和祖先将被存储在相同的ID – frobak

回答

1

好吧下面你会发现一个例子,如何实现你想要什么

你的模型应该是这样的:

class Organisations_Model extends CI_Model 
{ 

    private $arrOrganisationsGroupedByParent = array(); 
    private $objOrganisationsTree = false; 

    public function loadOrganisations() 
    { 
     $query = $this->db 
      ->select('o.*, if (oh.ancestor!=o.org_id, oh.ancestor, 0) AS parent', false) 
      ->from("organisations o") 
      ->join("org_hierarchy AS oh", "o.org_id = oh.descendant","left") 
      ->get(); 

     $arrOrganisations = $query->result("Organisations_Object"); 

     foreach($arrOrganisations AS $objItem) 
     { 
      $this->arrOrganisationsGroupedByParent[$objItem->parent][] = $objItem; 
     } 
    } 

    public function getTree() 
    { 
     $this->loadOrganisations(); 
     $this->objOrganisationsTree = new Organisations_Object(); 
     $this->createTree($this->objOrganisationsTree); 
     return $this->objOrganisationsTree; 
    } 


    private function createTree($node) 
    { 
     if (isset($this->arrOrganisationsGroupedByParent[$node->org_id])) 
     { 
      foreach($this->arrOrganisationsGroupedByParent[$node->org_id] AS $objItem) 
      { 
       //echo $objItem->org_id."<br />"; 
       $node->addChild($objItem); 
      } 
     } 

     foreach($node->arrChildObjects AS $objChild) 
     { 
      $this->createTree($objChild); 
     } 
    } 
} 

class Organisations_Object 
{ 
    public $arrChildObjects = array(); 
    public $org_id = 0; 
    public $parent = -1; 

    public function addChild($node) 
    { 
     $this->arrChildObjects[] = $node; 
    } 
} 

Note: You have in your model an additional Class called Organisations_Object - don't miss that one !

后只需简单地调用Controller中的getTree方法即可。

至于你的控制器为例只是把这两个函数和

public function testtree() 
{ 
    $this->load->model("Organisations_Model"); 
    $objTree = $this->Organisations_Model->getTree(); 
    $this->printTree($objTree); 
} 

private function printTree($objTree) 
{ 
    echo "<ul>"; 

    foreach($objTree->arrChildObjects AS $objItem) 
    { 
     echo "<li>".$objItem->org_id."#".$objItem->org_name; 
     if (count($objItem->arrChildObjects) > 0) 
     { 
      $this->printTree($objItem); 
     } 
     echo "</li>"; 
    } 
    echo "</ul>"; 

} 
+0

谢谢你,大量感谢你的帮助。我得到一个错误'致命错误:67108864字节允许的内存大小已耗尽(试图分配72个字节)in'在这一行'$ this-> arrChildObjects [] = $ node;' – frobak

+1

hehe好吧 - 这意味着它的一个无限循环 - 我只写了下课 - 我看看它 – sintakonte

+0

Theres几乎没有在数据库中的任何数据,它应该真的需要67MB? – frobak

相关问题