PHP无限分类数组操作类

namespace util;

class EasyTree
{
    /**
     * 支持递归数组合并
     *
     * @param array $dest 原数组
     * @param array $res  覆盖的数组
     *
     * @return array
     */
    public function merge($dest, $res)
    {
        $res = is_array($res) ? $res : [];
        foreach ($dest as $k => $v) {
            $res[$k] = isset($res[$k]) ? $res[$k] : $v;
            $res[$k] = is_array($res[$k]) ? $this->merge($v, $res[$k]) : $res[$k];
        }

        return $res;
    }

    /**
     * 返回多层栏目
     *
     * @param        $data     操作的数组
     * @param int    $pid      一级PID的值
     * @param string $html     栏目名称前缀
     * @param string $fieldPri 唯一键名,如果是表则是表的主键
     * @param string $fieldPid 父ID键名
     * @param int    $level    不需要传参数(执行时调用)
     *
     * @return array
     */
    public function channelLevel(
        $data,
        $pid = 0,
        $html = " ",
        $fieldPri = 'cid',
        $fieldPid = 'pid',
        $level = 1
    ) {
        if (empty($data)) {
            return [];
        }
        $arr = [];
        foreach ($data as $v) {
            if ($v[$fieldPid] == $pid) {
                $arr[$v[$fieldPri]]           = $v;
                $arr[$v[$fieldPri]]['_level'] = $level;
                $arr[$v[$fieldPri]]['_html']  = str_repeat($html, $level - 1);
                $arr[$v[$fieldPri]]["_data"]  = $this->channelLevel(
                    $data,
                    $v[$fieldPri],
                    $html,
                    $fieldPri,
                    $fieldPid,
                    $level + 1
                );
            }
        }

        return $arr;
    }

    /**
     * 获得栏目列表
     *
     * @param        $arr      栏目数据
     * @param int    $pid      操作的栏目
     * @param string $html     栏目名前字符
     * @param string $fieldPri 表主键
     * @param string $fieldPid 父id
     * @param int    $level    等级
     *
     * @return array
     */
    public function channelList(
        $arr,
        $pid = 0,
        $html = " ",
        $fieldPri = 'cid',
        $fieldPid = 'pid',
        $level = 1
    ) {
        $pid  = is_array($pid) ? $pid : [$pid];
        $data = [];
        foreach ($pid as $id) {
            $res = $this->_channelList(
                $arr,
                $id,
                $html,
                $fieldPri,
                $fieldPid,
                $level
            );
            foreach ($res as $k => $v) {
                $data[$k] = $v
            }
        }
        if (empty($data)) {
            return $data;
        }
        foreach ($data as $n => $m) {
            if ($m['_level'] == 1) {
                continue;
            }
            $data[$n]['_first'] = false;
            $data[$n]['_end']   = false;
            if ( ! isset($data[$n - 1])
                || $data[$n - 1]['_level'] != $m['_level']
            ) {
                $data[$n]['_first'] = true;
            }
            if (isset($data[$n + 1])
                && $data[$n]['_level'] > $data[$n + 1]['_level']
            ) {
                $data[$n]['_end'] = true;
            }
        }
        //更新key为栏目主键
        $category = [];
        foreach ($data as $d) {
            $category[$d[$fieldPri]] = $d;
        }

        return $category;
    }

    //只供channelList方法使用
    private function _channelList(
        $data,
        $pid = 0,
        $html = " ",
        $fieldPri = 'cid',
        $fieldPid = 'pid',
        $level = 1
    ) {
        if (empty($data)) {
            return [];
        }
        $arr = [];
        foreach ($data as $v) {
            $id = $v[$fieldPri];
            if ($v[$fieldPid] == $pid) {
                $v['_level'] = $level;
                $v['_html']  = str_repeat($html, $level - 1);
                array_push($arr, $v);
                $tmp = $this->_channelList(
                    $data,
                    $id,
                    $html,
                    $fieldPri,
                    $fieldPid,
                    $level + 1
                );
                $arr = array_merge($arr, $tmp);
            }
        }

        return $arr;
    }

    /**
     * 获得树状数据
     *
     * @param        $data     数据
     * @param        $title    字段名
     * @param string $fieldPri 主键id
     * @param string $fieldPid 父id
     *
     * @return array
     */
    public function tree($data, $title, $fieldPri = 'cid', $fieldPid = 'pid')
    {
        if ( ! is_array($data) || empty($data)) {
            return [];
        }
        $arr = $this->channelList($data, 0, '', $fieldPri, $fieldPid);
        foreach ($arr as $k => $v) {
            $str = "";
            if ($v['_level'] > 2) {
                for ($i = 1; $i < $v['_level'] - 1; $i++) {
                    $str .= "│&nbsp;&nbsp;&nbsp;&nbsp;";
                }
            }
            if ($v['_level'] != 1) {
                $t = $title ? $v[$title] : '';
                if (isset($arr[$k + 1])
                    && $arr[$k + 1]['_level'] >= $arr[$k]['_level']
                ) {
                    $arr[$k]['_'.$title] = $str."├─ ".$v['_html'].$t;
                } else {
                    $arr[$k]['_'.$title] = $str."└─ ".$v['_html'].$t;
                }
            } else {
                $arr[$k]['_'.$title] = $v[$title];
            }
        }
        //设置主键为$fieldPri
        $data = [];
        foreach ($arr as $d) {
            //            $data[$d[$fieldPri]] = $d;
            $data[] = $d;
        }

        return $data;
    }

    /**
     * 获得所有父级栏目
     *
     * @param        $data     栏目数据
     * @param        $sid      子栏目
     * @param string $fieldPri 唯一键名,如果是表则是表的主键
     * @param string $fieldPid 父ID键名
     *
     * @return array
     */
    public function parentChannel(
        $data,
        $sid,
        $fieldPri = 'cid',
        $fieldPid = 'pid'
    ) {
        if (empty($data)) {
            return $data;
        } else {
            $arr = [];
            foreach ($data as $v) {
                if ($v[$fieldPri] == $sid) {
                    $arr[] = $v;
                    $_n    = $this->parentChannel(
                        $data,
                        $v[$fieldPid],
                        $fieldPri,
                        $fieldPid
                    );
                    if ( ! empty($_n)) {
                        $arr = array_merge($arr, $_n);
                    }
                }
            }

            return $arr;
        }
    }

    /**
     * 判断$s_cid是否是$d_cid的子栏目
     *
     * @param        $data     栏目数据
     * @param        $sid      子栏目id
     * @param        $pid      父栏目id
     * @param string $fieldPri 主键
     * @param string $fieldPid 父id字段
     *
     * @return bool
     */
    public function isChild(
        $data,
        $sid,
        $pid,
        $fieldPri = 'cid',
        $fieldPid = 'pid'
    ) {
        $_data = $this->channelList($data, $pid, '', $fieldPri, $fieldPid);
        foreach ($_data as $c) {
            //目标栏目为源栏目的子栏目
            if ($c[$fieldPri] == $sid) {
                return true;
            }
        }

        return false;
    }

    /**
     * 检测是不否有子栏目
     *
     * @param        $data     栏目数据
     * @param        $cid      要判断的栏目cid
     * @param string $fieldPid 父id表字段名
     *
     * @return bool
     */
    public function hasChild($data, $cid, $fieldPid = 'pid')
    {
        foreach ($data as $d) {
            if ($d[$fieldPid] == $cid) {
                return true;
            }
        }

        return false;
    }

    /**
     * 递归实现迪卡尔乘积
     *
     * @param       $arr 操作的数组
     * @param array $tmp
     *
     * @return array
     */
    public function descarte($arr, $tmp = [])
    {
        $n_arr = [];
        foreach (array_shift($arr) as $v) {
            $tmp[] = $v;
            if ($arr) {
                $this->descarte($arr, $tmp);
            } else {
                $n_arr[] = $tmp;
            }
            array_pop($tmp);
        }

        return $n_arr;
    }

    /**
     * 从数组中移除给定的值
     *
     * @param array $data   原数组数据
     * @param array $values 要移除的值
     *
     * @return array
     */
    public function del(array $data, array $values)
    {
        $news = [];
        foreach ($data as $key => $d) {
            if ( ! in_array($d, $values)) {
                $news[$key] = $d;
            }
        }

        return $news;
    }

    /**
     * 根据键名获取数据
     * 如果键名不存在时返回默认值
     *
     * @param array  $data
     * @param string $key   名称
     * @param mixed  $value 默认值
     *
     * @return array|mixed|null
     */
    public function get(array $data, $key, $value = null)
    {
        $exp = explode('.', $key);
        foreach ((array)$exp as $d) {
            if (isset($data[$d])) {
                $data = $data[$d];
            } else {
                return $value;
            }
        }

        return $data;
    }

    /**
     * 排队字段获取数据
     *
     * @param array $data    数据
     * @param array $extName 排除的字段
     *
     * @return array
     */
    public static function getExtName(array $data, array $extName)
    {
        $extData = [];
        foreach ((array)$data as $k => $v) {
            if ( ! in_array($k, $extName)) {
                $extData[$k] = $v;
            }
        }

        return $extData;
    }

    /**
     * 设置数组元素值支持点语法
     *
     * @param array $data
     * @param       $key
     * @param       $value
     *
     * @return array
     */
    public function set(array $data, $key, $value)
    {
        $tmp =& $data;
        foreach (explode('.', $key) as $d) {
            if ( ! isset($tmp[$d])) {
                $tmp[$d] = [];
            }
            $tmp = &$tmp[$d];
        }
        $tmp = $value;

        return $data;
    }

    /**
     * 将数组键名变成大写或小写
     *
     * @param array $arr  数组
     * @param int   $type 转换方式 1大写   0小写
     *
     * @return array
     */
    public function keyCase($arr, $type = 0)
    {
        $func = $type ? 'strtoupper' : 'strtolower';
        $data = []; //格式化后的数组
        foreach ($arr as $k => $v) {
            $k        = $func($k);
            $data[$k] = is_array($v) ? $this->keyCase($v, $type) : $v;
        }

        return $data;
    }

    /**
     * 不区分大小写检测数据键名是否存在
     *
     * @param $key
     * @param $arr
     *
     * @return bool
     */
    public function keyExists($key, $arr)
    {
        return array_key_exists(strtolower($key), $this->keyExists($arr));
    }

    /**
     * 将数组中的值全部转为大写或小写
     *
     * @param array $arr
     * @param int   $type 类型 1值大写 0值小写
     *
     * @return array
     */
    public function valueCase($arr, $type = 0)
    {
        $func = $type ? 'strtoupper' : 'strtolower';
        $data = []; //格式化后的数组
        foreach ($arr as $k => $v) {
            $data[$k] = is_array($v) ? $this->valueCase($v, $type) : $func($v);
        }

        return $data;
    }

    /**
     * 数组进行整数映射转换
     *
     * @param       $arr
     * @param array $map
     *
     * @return mixed
     */
    public function intToString(
        $arr,
        array $map = ['status' => ['0' => '禁止', '1' => '启用']]
    ) {
        foreach ($map as $name => $m) {
            if (isset($arr[$name]) && array_key_exists($arr[$name], $m)) {
                $arr['_'.$name] = $m[$arr[$name]];
            }
        }

        return $arr;
    }

    /**
     * 数组中的字符串数字转为INT类型
     *
     * @param $data
     *
     * @return mixed
     */
    public function stringToInt($data)
    {
        $tmp = $data;
        foreach ((array)$tmp as $k => $v) {
            $tmp[$k] = is_array($v) ? $this->stringToInt($v)
                : (is_numeric($v) ? intval($v) : $v);
        }

        return $tmp;
    }

    /**
     * 根据下标过滤数据元素
     *
     * @param array $data 原数组数据
     * @param       $keys 参数的下标
     * @param int   $type 1 存在在$keys时过滤  0 不在时过滤
     *
     * @return array
     */
    public function filterKeys(array $data, $keys, $type = 1)
    {
        $tmp = $data;
        foreach ($data as $k => $v) {
            if ($type == 1) {
                //存在时过滤
                if (in_array($k, $keys)) {
                    unset($tmp[$k]);
                }
            } else {
                //不在时过滤
                if ( ! in_array($k, $keys)) {
                    unset($tmp[$k]);
                }
            }
        }

        return $tmp;
    }
}

转载于:https://my.oschina.net/u/3483680/blog/1823112

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值