2016-11-28 24 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

相關問題