您的当前位置:首页>全部文章>文章详情

php二维数据转为带线条的树形结构数据

发表于:2024-09-26 10:37:20浏览:136次TAG: #PHP #树形

引言

本文将详细介绍php二维数据转为带线条的树形结构数据,并提供整理的源码和通过示例代码进行说明。

调用

源数据

[
    {
        "id": "1",
        "pid": 0,
        "name": "一级栏目一"
    },
    {
        "id": "2",
        "pid": 0,
        "name": "一级栏目二"
    },
    {
        "id": "3",
        "pid": 1,
        "name": "二级栏目一"
    },
    {
        "id": "4",
        "pid": 1,
        "name": "二级栏目二"
    },
    {
        "id": "5",
        "pid": 2,
        "name": "二级栏目三"
    },
    {
        "id": "6",
        "pid": 3,
        "name": "三级栏目一"
    },
    {
        "id": "7",
        "pid": 3,
        "name": "三级栏目二"
    }
]

初始化

$instance = \app\common\utils\Tree::instance()->init($data);

生成树形结构数据

$tree_data = $instance->getTreeOrg(0);
// 输出
[
    {
        "id": "1",
        "pid": 0,
        "name": "一级栏目一",
        "spacer": "",
        "_child": [
            {
                "id": "3",
                "pid": 1,
                "name": "二级栏目一",
                "spacer": " ├",
                "_child": [
                    {
                        "id": "6",
                        "pid": 3,
                        "name": "三级栏目一",
                        "spacer": " │ ├",
                        "_child": []
                    },
                    {
                        "id": "7",
                        "pid": 3,
                        "name": "三级栏目二",
                        "spacer": " │ └",
                        "_child": []
                    }
                ]
            },
            {
                "id": "4",
                "pid": 1,
                "name": "二级栏目二",
                "spacer": " └",
                "_child": []
            }
        ]
    },
    {
        "id": "2",
        "pid": 0,
        "name": "一级栏目二",
        "spacer": "",
        "_child": [
            {
                "id": "5",
                "pid": 2,
                "name": "二级栏目三",
                "spacer": " └",
                "_child": []
            }
        ]
    }
]

生成带符号的二维数组

$list = $instance->getTreeList($tree_data);
// 输出
[
    {
        "id": "1",
        "pid": 0,
        "name": " 一级栏目一",
        "spacer": "",
        "haschild": 1
    },
    {
        "id": "3",
        "pid": 1,
        "name": " ├ 二级栏目一",
        "spacer": " ├",
        "haschild": 1
    },
    {
        "id": "6",
        "pid": 3,
        "name": " │ ├ 三级栏目一",
        "spacer": " │ ├",
        "haschild": 0
    },
    {
        "id": "7",
        "pid": 3,
        "name": " │ └ 三级栏目二",
        "spacer": " │ └",
        "haschild": 0
    },
    {
        "id": "4",
        "pid": 1,
        "name": " └ 二级栏目二",
        "spacer": " └",
        "haschild": 0
    },
    {
        "id": "2",
        "pid": 0,
        "name": " 一级栏目二",
        "spacer": "",
        "haschild": 1
    },
    {
        "id": "5",
        "pid": 2,
        "name": " └ 二级栏目三",
        "spacer": " └",
        "haschild": 0
    }
]

生成html的option

$options = $instance->getHtmlOption(0);
// 输出
<option value=1  >一级栏目一</option>
<option value=3  > ├二级栏目一</option>
<option value=6  > │ ├三级栏目一</option>
<option value=7  > │ └三级栏目二</option>
<option value=4  > └二级栏目二</option>
<option value=2  >一级栏目二</option>
<option value=5  > └二级栏目三</option>

生成html的ul

$ul = $instance->getHtmlUl(0);
// 输出
<li value=1  >一级栏目一 
    <ul >
        <li value=3  >二级栏目一 
            <ul >
                <li value=6  >三级栏目一 </li>
                <li value=7  >三级栏目二 </li>
            </ul>
        </li>
        <li value=4  >二级栏目二 </li>
    </ul>
</li>
<li value=2  >一级栏目二 
    <ul >
        <li value=5  >二级栏目三 </li>
    </ul>
</li>

<?php
namespace app\common\utils;
/**
 * 树型
 */
class Tree
{
    protected static $instance;
    /**
     * 生成树型结构所需要的2维数组
     * @var array
     */
    public $arr = [];

    /**
     * 生成树型结构所需修饰符号,可以换成图片
     * @var array
     */
    public $icon = array('│', '├', '└');
    public $nbsp = " ";
    public $pidname = 'pid';
    public $pk = 'id';
    public $childname = '_child';

    /**
     * 初始化
     * @access public
     * @return Tree
     */
    public static function instance()
    {
        if (is_null(self::$instance)) {
            self::$instance = new static();
        }
        return self::$instance;
    }

    /**
     * 初始化方法
     * @param array  $arr     2维数组,例如:
     *      array(
     *      0 => array('id'=>'1','pid'=>0,'name'=>'一级栏目一'),
     *      1 => array('id'=>'2','pid'=>0,'name'=>'一级栏目二'),
     *      2 => array('id'=>'3','pid'=>1,'name'=>'二级栏目一'),
     *      3 => array('id'=>'4','pid'=>1,'name'=>'二级栏目二'),
     *      4 => array('id'=>'5','pid'=>2,'name'=>'二级栏目三'),
     *      5 => array('id'=>'6','pid'=>3,'name'=>'三级栏目一'),
     *      6 => array('id'=>'7','pid'=>3,'name'=>'三级栏目二')
     *      )
     * @param string $pidname 父字段名称
     * @param string $nbsp    空格占位符
     * @return Tree
     */
    public function init(array $arr = [], string $pk = null,string $childname = null,string $pidname = null, string $nbsp = null)
    {
        $this->arr = $arr;
        if (!is_null($pidname)) {
            $this->pidname = $pidname;
        }
        if (!is_null($nbsp)) {
            $this->nbsp = $nbsp;
        }
        if(!is_null($pk)){
            $this->pk  = $pk;
        }
        if(!is_null($childname)){
            $this->pk  = $childname;
        }
        return $this;
    }

    /**
     * 得到子级数组
     * @param int $myid
     * @return array
     */
    public function getChild(int $myid)
    {
        $newarr = [];
        foreach ($this->arr as $value) {
            if (!isset($value[$this->pk])) {
                continue;
            }
            if ($value[$this->pidname] == $myid) {
                $newarr[$value[$this->pk]] = $value;
            }
        }
        return $newarr;
    }

    /**
     * 读取指定节点的所有孩子节点
     * @param int $myid
     * @param bool $withself
     * @return array
     */
    public function getChildren(int $myid, bool $withself = false)
    {
        $newarr = [];
        foreach ($this->arr as $value) {
            if (!isset($value[$this->pk])) {
                continue;
            }
            if ($value[$this->pidname] == $myid) {
                $newarr[] = $value;
                $newarr = array_merge($newarr, $this->getChildren($value[$this->pk]));
            } elseif ($withself && $value[$this->pk] == $myid) {
                $newarr[] = $value;
            }
        }
        return $newarr;
    }

    /**
     * 读取指定节点的所有孩子节点ID
     * @param int $myid
     * @param bool $withself
     * @return array
     */
    public function getChildrenIds(int $myid, bool $withself = false)
    {
        $childrenlist = $this->getChildren($myid, $withself);
        $childrenids = [];
        foreach ($childrenlist as $k => $v) {
            $childrenids[] = $v[$this->pk];
        }
        return $childrenids;
    }

    /**
     * 得到当前位置父辈数组
     * @param int $myid
     * @return array
     */
    public function getParent(int $myid)
    {
        $pid = 0;
        $newarr = [];
        foreach ($this->arr as $value) {
            if (!isset($value[$this->pk])) {
                continue;
            }
            if ($value[$this->pk] == $myid) {
                $pid = $value[$this->pidname];
                break;
            }
        }
        if ($pid) {
            foreach ($this->arr as $value) {
                if ($value[$this->pk] == $pid) {
                    $newarr[] = $value;
                    break;
                }
            }
        }
        return $newarr;
    }

    /**
     * 得到当前位置所有父辈数组
     * @param int $myid
     * @param bool $withself
     * @return array
     */
    public function getParents(int $myid, bool $withself = false)
    {
        $pid = 0;
        $newarr = [];
        foreach ($this->arr as $value) {
            if (!isset($value[$this->pk])) {
                continue;
            }
            if ($value[$this->pk] == $myid) {
                if ($withself) {
                    $newarr[] = $value;
                }
                $pid = $value[$this->pidname];
                break;
            }
        }
        if ($pid) {
            $arr = $this->getParents($pid, true);
            $newarr = array_merge($arr, $newarr);
        }
        return $newarr;
    }

    /**
     * 读取指定节点所有父类节点ID
     * @param int $myid
     * @param bool $withself
     * @return array
     */
    public function getParentsIds(int $myid, bool $withself = false)
    {
        $parentlist = $this->getParents($myid, $withself);
        $parentsids = [];
        foreach ($parentlist as $k => $v) {
            $parentsids[] = $v[$this->pk];
        }
        return $parentsids;
    }

    /**
     * 树型结构Option
     * @param int    $myid        表示获得这个ID下的所有子级
     * @param string $itemtpl     条目模板 如:"<option value=@id @selected @disabled>@spacer@name</option>"
     * @param mixed  $selectedids 被选中的ID,比如在做树型下拉框的时候需要用到
     * @param mixed  $disabledids 被禁用的ID,比如在做树型下拉框的时候需要用到
     * @param string $itemprefix  每一项前缀
     * @param string $toptpl      顶级栏目的模板
     * @return string
     */
    public function getHtmlOption(int $myid, string $itemtpl = "<option value=@id @selected @disabled>@spacer@name</option>",string $selectedids = '',string $disabledids = '',string $itemprefix = '',string $toptpl = '')
    {
        $ret = '';
        $number = 1;
        $childs = $this->getChild($myid);
        if ($childs) {
            $total = count($childs);
            foreach ($childs as $value) {
                $id = $value[$this->pk];
                $j = $k = '';
                if ($number == $total) {
                    $j .= $this->icon[2];
                    $k = $itemprefix ? $this->nbsp : '';
                } else {
                    $j .= $this->icon[1];
                    $k = $itemprefix ? $this->icon[0] : '';
                }
                $spacer = $itemprefix ? $itemprefix . $j : '';
                $selected = $selectedids && in_array($id, (is_array($selectedids) ? $selectedids : explode(',', $selectedids))) ? 'selected' : '';
                $disabled = $disabledids && in_array($id, (is_array($disabledids) ? $disabledids : explode(',', $disabledids))) ? 'disabled' : '';
                $value = array_merge($value, array('selected' => $selected, 'disabled' => $disabled, 'spacer' => $spacer));
                $value = array_combine(array_map(function ($k) {
                    return '@' . $k;
                }, array_keys($value)), $value);
                $nstr = strtr((($value["@{$this->pidname}"] == 0 || $this->getChild($id)) && $toptpl ? $toptpl : $itemtpl), $value);
                $ret .= $nstr;
                $ret .= $this->getHtmlOption($id, $itemtpl, $selectedids, $disabledids, $itemprefix . $k . $this->nbsp, $toptpl);
                $number++;
            }
        }
        return $ret;
    }

    /**
     * 树型结构UL
     * @param int    $myid        表示获得这个ID下的所有子级
     * @param string $itemtpl     条目模板 如:"<li value=@id @selected @disabled>@name @childlist</li>"
     * @param string $selectedids 选中的ID
     * @param string $disabledids 禁用的ID
     * @param string $wraptag     子列表包裹标签
     * @param string $wrapattr    子列表包裹属性
     * @return string
     */
    public function getHtmlUl(int $myid, string $itemtpl = "<li value=@id @selected @disabled>@name @childlist</li>", string $selectedids = '', string $disabledids = '', string $wraptag = 'ul', string $wrapattr = '')
    {
        $str = '';
        $childs = $this->getChild($myid);
        if ($childs) {
            foreach ($childs as $value) {
                $id = $value[$this->pk];
                unset($value['child']);
                $selected = $selectedids && in_array($id, (is_array($selectedids) ? $selectedids : explode(',', $selectedids))) ? 'selected' : '';
                $disabled = $disabledids && in_array($id, (is_array($disabledids) ? $disabledids : explode(',', $disabledids))) ? 'disabled' : '';
                $value = array_merge($value, array('selected' => $selected, 'disabled' => $disabled));
                $value = array_combine(array_map(function ($k) {
                    return '@' . $k;
                }, array_keys($value)), $value);
                $nstr = strtr($itemtpl, $value);
                $childdata = $this->getHtmlUl($id, $itemtpl, $selectedids, $disabledids, $wraptag, $wrapattr);
                $childlist = $childdata ? "<{$wraptag} {$wrapattr}>" . $childdata . "</{$wraptag}>" : "";
                $str .= strtr($nstr, array('@childlist' => $childlist));
            }
        }
        return $str;
    }

    /**
     * 获取树状数组
     * @param int $myid
     * @param string $itemprefix
     * @return array
     */
    public function getTreeOrg(int $myid, string $itemprefix = '')
    {
        $childs = $this->getChild($myid);
        $n = 0;
        $data = [];
        $number = 1;
        if ($childs) {
            $total = count($childs);
            foreach ($childs as $id => $value) {
                $j = $k = '';
                if ($number == $total) {
                    $j .= $this->icon[2];
                    $k = $itemprefix ? $this->nbsp : '';
                } else {
                    $j .= $this->icon[1];
                    $k = $itemprefix ? $this->icon[0] : '';
                }
                $spacer = $itemprefix ? $itemprefix . $j : '';
                $value['spacer'] = $spacer;
                $data[$n] = $value;
                $data[$n][$this->childname] = $this->getTreeOrg($id, $itemprefix . $k . $this->nbsp);
                $n++;
                $number++;
            }
        }
        return $data;
    }

    /**
     * 将getTreeOrg的结果返回为二维数组
     * @param array $data
     * @param string $field
     * @return array
     */
    public function getTreeList(array $data = [], string $field = 'name')
    {
        $arr = [];
        foreach ($data as $k => $v) {
            $childlist = isset($v[$this->childname]) ? $v[$this->childname] : [];
            unset($v[$this->childname]);
            $v[$field] = html_entity_decode($v['spacer'] . ' ' . $v[$field]);
            $v['haschild'] = $childlist ? 1 : 0;
            if ($v[$this->pk]) {
                $arr[] = $v;
            }
            if ($childlist) {
                $arr = array_merge($arr, $this->getTreeList($childlist, $field));
            }
        }
        return $arr;
    }
}