增加节点读取器

This commit is contained in:
邹景立 2017-02-23 14:56:34 +08:00
parent 7c5c080af8
commit 93292e6f8d
4 changed files with 47 additions and 108 deletions

View File

@ -4,6 +4,7 @@ namespace app\admin\controller;
use controller\BasicAdmin; use controller\BasicAdmin;
use library\Data; use library\Data;
use library\Node;
use library\Tools; use library\Tools;
use think\Db; use think\Db;
@ -55,7 +56,7 @@ class Menu extends BasicAdmin {
protected function _form_filter(&$vo) { protected function _form_filter(&$vo) {
if ($this->request->isGet()) { if ($this->request->isGet()) {
$_menus = Db::name($this->table)->where('status', '1')->order('sort ASC,id ASC')->select(); $_menus = Db::name($this->table)->where('status', '1')->order('sort desc,id desc')->select();
$_menus[] = ['title' => '顶级菜单', 'id' => '0', 'pid' => '-1']; $_menus[] = ['title' => '顶级菜单', 'id' => '0', 'pid' => '-1'];
$menus = Tools::arr2table($_menus); $menus = Tools::arr2table($_menus);
foreach ($menus as $key => &$menu) { foreach ($menus as $key => &$menu) {
@ -70,6 +71,7 @@ class Menu extends BasicAdmin {
} }
} }
} }
$this->assign('nodes', Node::getNodeTree(APP_PATH));
$this->assign('menus', $menus); $this->assign('menus', $menus);
} }
} }

View File

@ -2,7 +2,7 @@
<div class="layui-form-item"> <div class="layui-form-item">
<label class="layui-form-label">上级菜单</label> <label class="layui-form-label">上级菜单</label>
<div class="layui-input-block"> <div class="layui-input-block">
<select name='pid'> <select name='pid' class='layui-select full-width' style='display:block'>
<!--{foreach $menus as $menu}--> <!--{foreach $menus as $menu}-->
<!--{eq name='menu.id' value='$vo.pid|default=0'}--> <!--{eq name='menu.id' value='$vo.pid|default=0'}-->
<option selected value='{$menu.id}'>{$menu.spl}{$menu.title}</option> <option selected value='{$menu.id}'>{$menu.spl}{$menu.title}</option>
@ -22,7 +22,7 @@
<div class="layui-form-item"> <div class="layui-form-item">
<label class="layui-form-label">菜单链接</label> <label class="layui-form-label">菜单链接</label>
<div class="layui-input-block"> <div class="layui-input-block">
<input type="tel" name="url" required="required" title="请输入菜单链接" placeholder="请输入菜单链接" value="{$vo.url|default='#'}" class="layui-input"> <input type="text" onblur="(this.value === '') && (this.value = '#')" name="url" autocomplete="off" required="required" title="请输入菜单链接" placeholder="请输入菜单链接" value="{$vo.url|default='#'}" class="layui-input typeahead">
</div> </div>
</div> </div>
<div class="layui-form-item"> <div class="layui-form-item">
@ -42,6 +42,9 @@
<button class="layui-btn layui-btn-danger" type='button' data-close>取消编辑</button> <button class="layui-btn layui-btn-danger" type='button' data-close>取消编辑</button>
</div> </div>
<script> <script>
window.form.render(); require(['bootstrap.typeahead'], function () {
var subjects = JSON.parse('{$nodes|json_encode}');
$('.typeahead').typeahead({source: subjects, items: 5});
});
</script> </script>
</form> </form>

View File

@ -3,126 +3,59 @@
namespace library; namespace library;
/** /**
* 代码节点读取工具 * 代码节点分析器
* *
* @author shaobo <luoshaobo@cuci.cc> * @author Anyon <zoujingli@qq.com>
* @date 2016-10-21 * @date 2017/02/23 14:46
*/ */
class Node { class Node {
/**
* 获取节点列表
* @param string $path
* @param array $nodes
* @return array
*/
static public function getNodeTree($path, $nodes = []) {
foreach (self::getFilePaths($path) as $vo) {
if (stripos($vo, DS . 'controller' . DS) === false) {
continue;
}
$_tmp = explode(DS, $vo);
$controllerName = rtrim(array_pop($_tmp), '.php');
array_pop($_tmp);
$moduleName = array_pop($_tmp);
$className = config('app_namespace') . "\\{$moduleName}\\controller\\{$controllerName}";
if (!class_exists($className)) {
continue;
}
foreach (get_class_methods($className) as $actionName) {
if ($actionName[0] !== '_') {
$nodes[] = strtolower("{$moduleName}/{$controllerName}/{$actionName}");
}
}
}
return $nodes;
}
/** /**
* 获取所有PHP文件 * 获取所有PHP文件
* @param string $path * @param string $path
* @param array $data * @param array $data
* @param string $ext
* @return array * @return array
*/ */
static public function getTree($path, $data = []) { static public function getFilePaths($path, $data = [], $ext = 'php') {
foreach (scandir($path) as $dir) { foreach (scandir($path) as $dir) {
if ($dir[0] === '.') { if ($dir[0] === '.') {
continue; continue;
} }
$tmp = realpath($path . DIRECTORY_SEPARATOR . $dir); $tmp = realpath($path . DS . $dir);
if ($tmp && (is_dir($tmp) || pathinfo($tmp, PATHINFO_EXTENSION) === 'php')) { if ($tmp && (is_dir($tmp) || pathinfo($tmp, PATHINFO_EXTENSION) === $ext)) {
is_dir($tmp) ? $data = array_merge($data, self::getTree($tmp)) : $data[] = $tmp; is_dir($tmp) ? $data = array_merge($data, self::getFilePaths($tmp)) : $data[] = $tmp;
} }
} }
return $data; return $data;
} }
/**
* 处理类继承关系
* @param array $data
* @param string $class
* @param array $params
*/
static public function setSubClass(&$data, $class, &$params) {
foreach ($data as $key => &$value) {
if (isset($value['extends']) && $value['extends'] === $class) {
$value['attribute'] = array_merge($params['attribute'], $value['attribute']);
$value['method'] = array_merge($params['method'], $value['method']);
array_unique($value['method']);
array_unique($value['attribute']);
self::setSubClass($data, $key, $value);
}
}
}
/**
* 获取节点数据
* @return array
*/
static public function getNodeArrayTree() {
$list = self::getTree(ROOT_PATH);
$data = [];
$dirspace = [];
foreach ($list as $file) {
$content = file_get_contents($file);
// 解析空间及名称
preg_match("|namespace\s*(.*?)\s*;.*?class\s*(\w+)\s*|is", $content, $matches);
if (count($matches) > 1) {
$name = "{$matches[1]}\\{$matches[2]}";
$dir = dirname($file);
$class = ['method' => [], 'attribute' => [], 'namespace' => $matches[1], 'classname' => $matches[2]];
$dirspace[$dir] = $matches[1];
$class['dir'] = $dir;
// 解析类方法
preg_match_all("|public\s*function\s*(\w+)\s*\(|is", $content, $matches);
if (!empty($matches[1])) {
foreach ($matches[1] as $v) {
!in_array($v, ['_initialize', '__construct']) && $class['method'][] = $v;
}
}
// 解析简单的类属性
preg_match_all("|public\s*\\$(\w+)\s*=\s*(\w+)\s*;|is", $content, $matches);
if (!empty($matches[1]) && !empty($matches[2])) {
foreach ($matches[1] as $k => $v) {
$class['attribute'][$v] = $matches[2][$k];
}
}
// 类继承分析
preg_match("|extends\s*(\w+)\s*\{|is", $content, $matches);
if (!empty($matches[1])) {
// 直接继承
if ($matches[1][0] === '\\') {
$class['extends'] = $matches[1];
break;
}
// use 继承
if (preg_match_all("|use\s*([\w\\\]*)\s*\;|is", $content, $use) && !empty($use[1])) {
foreach ($use[1] as $c) {
$attr = explode('\\', $c);
if ($matches[1] === end($attr)) {
$class['extends'] = $c;
break;
}
}
}
// 同空间继续,需要修复
empty($class['extends']) && ($class['extends'] = '?' . $matches[1]);
}
$data[$name] = $class;
}
}
// 命名空间修复
foreach ($data as &$vo) {
if (!empty($vo['extends']) && $vo['extends'][0] === '?' && isset($dirspace[$vo['dir']])) {
$vo['extends'] = $dirspace[$vo['dir']] . '\\' . trim($vo['extends'], '?');
}
}
// 类继续方法参数合并
foreach ($data as $key => $value) {
empty($value['extends']) && self::setSubClass($data, $key, $value);
}
// 过滤掉非控制器的域名
foreach ($data as $k => &$v) {
if (!preg_match('/app.*?controller/', $k)) {
unset($data[$k]);
continue;
}
//获取模块名
$v['module'] = substr(str_replace("app\\", "", $k), 0, strpos(str_replace("app\\", "", $k), "\\"));
}
return $data;
}
} }

View File

@ -17,6 +17,7 @@ require.config({
'jquery.icheck': ['//cdn.bootcss.com/iCheck/1.0.2/icheck.min'], 'jquery.icheck': ['//cdn.bootcss.com/iCheck/1.0.2/icheck.min'],
'jquery.cookies': ['//cdn.bootcss.com/jquery-cookie/1.4.1/jquery.cookie', '../plugs/jquery/jquery.cookie'], 'jquery.cookies': ['//cdn.bootcss.com/jquery-cookie/1.4.1/jquery.cookie', '../plugs/jquery/jquery.cookie'],
'bootstrap': ['//cdn.bootcss.com/bootstrap/3.3.6/js/bootstrap.min', '../plugs/bootstrap/js/bootstrap.min'], 'bootstrap': ['//cdn.bootcss.com/bootstrap/3.3.6/js/bootstrap.min', '../plugs/bootstrap/js/bootstrap.min'],
'bootstrap.typeahead': ['//cdn.bootcss.com/bootstrap-3-typeahead/4.0.2/bootstrap3-typeahead.min'],
'bootstrap.multiselect': ['//cdn.bootcss.com/bootstrap-multiselect/0.9.13/js/bootstrap-multiselect.min', '../plugs/multiselect/bootstrap-multiselect'], 'bootstrap.multiselect': ['//cdn.bootcss.com/bootstrap-multiselect/0.9.13/js/bootstrap-multiselect.min', '../plugs/multiselect/bootstrap-multiselect'],
// 自定义插件 // 自定义插件
'admin.plugs': ['plugs'], 'admin.plugs': ['plugs'],