2019-07-17 11:04:38 +08:00

198 lines
6.7 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://library.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
namespace library\tools;
use think\facade\Request;
/**
* 控制器节点管理器
* Class Node
* @package library\tools
*/
class Node
{
/**
* 忽略控制名的前缀
* @var array
*/
private static $ignoreController = [
'api.', 'wap.', 'web.',
];
/**
* 忽略控制的方法名
* @var array
*/
private static $ignoreAction = [
'_', 'redirect', 'assign', 'callback',
'initialize', 'success', 'error', 'fetch',
];
/**
* 获取标准访问节点
* @param string $node
* @return string
*/
public static function get($node = null)
{
if (empty($node)) return self::current();
if (count(explode('/', $node)) === 1) {
$node = Request::module() . '/' . Request::controller() . '/' . $node;
}
return self::parseString(trim($node));
}
/**
* 获取当前访问节点
* @return string
*/
public static function current()
{
return self::parseString(Request::module() . '/' . Request::controller() . '/' . Request::action());
}
/**
* 获取节点列表
* @param string $dir 控制器根路径
* @param array $nodes 额外数据
* @return array
* @throws \ReflectionException
*/
public static function getTree($dir, $nodes = [])
{
self::eachController($dir, function (\ReflectionClass $reflection, $prenode) use (&$nodes) {
foreach ($reflection->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
$action = strtolower($method->getName());
foreach (self::$ignoreAction as $ignore) if (stripos($action, $ignore) === 0) continue 2;
$nodes[] = $prenode . $action;
};
});
return $nodes;
}
/**
* 获取控制器节点列表
* @param string $dir 控制器根路径
* @param array $nodes 额外数据
* @return array
* @throws \ReflectionException
*/
public static function getClassTreeNode($dir, $nodes = [])
{
self::eachController($dir, function (\ReflectionClass $reflection, $prenode) use (&$nodes) {
list($node, $comment) = [trim($prenode, '/'), $reflection->getDocComment()];
$nodes[$node] = preg_replace('/^\/\*\*\*(.*?)\*.*?$/', '$1', preg_replace("/\s/", '', $comment));
if (stripos($nodes[$node], '@') !== false) $nodes[$node] = '';
});
return $nodes;
}
/**
* 获取方法节点列表
* @param string $dir 控制器根路径
* @param array $nodes 额外数据
* @return array
* @throws \ReflectionException
*/
public static function getMethodTreeNode($dir, $nodes = [])
{
self::eachController($dir, function (\ReflectionClass $reflection, $prenode) use (&$nodes) {
foreach ($reflection->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
$action = strtolower($method->getName());
foreach (self::$ignoreAction as $ignore) if (stripos($action, $ignore) === 0) continue 2;
$node = $prenode . $action;
$nodes[$node] = preg_replace('/^\/\*\*\*(.*?)\*.*?$/', '$1', preg_replace("/\s/", '', $method->getDocComment()));
if (stripos($nodes[$node], '@') !== false) $nodes[$node] = '';
}
});
return $nodes;
}
/**
* 控制器扫描回调
* @param string $dir
* @param callable $callable
* @throws \ReflectionException
*/
public static function eachController($dir, $callable)
{
foreach (Node::scanDir($dir) as $file) {
if (!preg_match("|/(\w+)/controller/(.+)\.php$|", strtr($file, '\\', '/'), $matches)) continue;
list($module, $controller) = [$matches[1], strtr($matches[2], '/', '.')];
foreach (self::$ignoreController as $ignore) if (stripos($controller, $ignore) === 0) continue 2;
if (class_exists($class = substr(strtr(env('app_namespace') . $matches[0], '/', '\\'), 0, -4))) {
call_user_func($callable, new \ReflectionClass($class), Node::parseString("{$module}/{$controller}/"));
}
}
}
/**
* 驼峰转下划线规则
* @param string $node 节点名称
* @return string
*/
public static function parseString($node)
{
if (count($nodes = explode('/', $node)) > 1) {
$dots = [];
foreach (explode('.', $nodes[1]) as $dot) {
$dots[] = trim(preg_replace("/[A-Z]/", "_\\0", $dot), "_");
}
$nodes[1] = join('.', $dots);
}
return strtolower(join('/', $nodes));
}
/**
* 获取所有PHP文件
* @param string $dir 目录
* @param array $data 额外数据
* @param string $ext 有文件后缀
* @return array
*/
public static function scanDir($dir, $data = [], $ext = 'php')
{
foreach (scandir($dir) as $curr) if (strpos($curr, '.') !== 0) {
$path = realpath($dir . DIRECTORY_SEPARATOR . $curr);
if (is_dir($path)) $data = array_merge($data, self::scanDir($path));
elseif (pathinfo($path, PATHINFO_EXTENSION) === $ext) $data[] = $path;
}
return $data;
}
/**
* 递归统计目录大小
* @param string $path 目录
* @return integer
*/
public static function totalDirSize($path)
{
list($total, $path) = [0, realpath($path)];
if (!file_exists($path)) return $total;
if (!is_dir($path)) return filesize($path);
if ($handle = opendir($path)) {
while ($file = readdir($handle)) if (!in_array($file, ['.', '..'])) {
$temp = $path . DIRECTORY_SEPARATOR . $file;
$total += (is_dir($temp) ? self::totalDirSize($temp) : filesize($temp));
}
if (is_resource($handle)) closedir($handle);
}
return $total;
}
}