php - 使用 Codeigniter 闭包表显示分层数据

标签 php mysql codeigniter hierarchical-data

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

但是我如何修改此查询以显示按父组织分组的所有组织的完整列表?

我可以使用以下查询查询并获取单个组织及其子组织,但如何修改查询以获取所有组织及其子组织?我肯定必须靠近吗?

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 |
+----+----------+------------+-----+

最佳答案

好吧,下面您将找到一个如何实现您想要的目标的示例

您的模型应如下所示:

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 方法即可。

作为 Controller 的示例,只需将这两个函数放入并从浏览器中调用它

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

}

关于php - 使用 Codeigniter 闭包表显示分层数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40842668/

相关文章:

PHP 将用户 ID 传递给 mysql 触发器

php - Codeigniter 3 - 我可以从 3 张图片中获取图片上传的 url 吗?

php - 从 iOS 向 php Web 服务发送请求

php - 如何从 Silex 中的 url 获取参数

mysql - 无法在 Mysql 中创建可更新 View

php - MySQL 中的动态导航菜单,PDO 显示一个实例

php - HTTP 转发 PLAINTEXT 警告

php - SSL 操作失败,代码为 1 : dh key too small

php - 如何使用循环向表中插入数据。?

php - 如何在 codeigniter 中使用 group by 来计算一些值?