mirror of
https://gitee.com/zoujingli/ThinkAdmin.git
synced 2026-06-07 20:48:09 +08:00
fix: 重构 ToolsExtend 文件系统操作工具
This commit is contained in:
parent
d8b984b2dc
commit
aef4e36c19
@ -108,7 +108,7 @@ class Library extends Service
|
||||
{
|
||||
// 动态加载全局配置
|
||||
[$dir, $ext] = [$this->app->getBasePath(), $this->app->getConfigExt()];
|
||||
ToolsExtend::findFilesArray($dir, 2, function (SplFileInfo $info) use ($ext) {
|
||||
ToolsExtend::find($dir, 2, function (SplFileInfo $info) use ($ext) {
|
||||
$info->isFile() && $info->getBasename() === "sys{$ext}" && include_once $info->getPathname();
|
||||
});
|
||||
if (is_file($file = "{$dir}common{$ext}")) include_once $file;
|
||||
|
||||
@ -338,13 +338,13 @@ CODE;
|
||||
private static function nextFile(string $class): string
|
||||
{
|
||||
[$snake, $items] = [Str::snake($class), [20010000000000]];
|
||||
ToolsExtend::findFilesArray(syspath('database/migrations'), 1, function (SplFileInfo $info) use ($snake, &$items) {
|
||||
ToolsExtend::find(syspath('database/migrations'), 1, function (SplFileInfo $info) use ($snake, &$items) {
|
||||
if ($info->isFile()) {
|
||||
$bname = pathinfo($info->getBasename(), PATHINFO_FILENAME);
|
||||
$items[] = $version = intval(substr($bname, 0, 14));
|
||||
if ($snake === substr($bname, 15) && unlink($info->getRealPath())) {
|
||||
if (is_dir($dataPath = $info->getPath() . DIRECTORY_SEPARATOR . $version)) {
|
||||
ToolsExtend::removeEmptyDirectory($dataPath);
|
||||
ToolsExtend::remove($dataPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -22,6 +22,7 @@ use Closure;
|
||||
use FilesystemIterator;
|
||||
use Generator;
|
||||
use SplFileInfo;
|
||||
use think\admin\Exception;
|
||||
|
||||
/**
|
||||
* 通用工具扩展
|
||||
@ -30,82 +31,31 @@ use SplFileInfo;
|
||||
*/
|
||||
class ToolsExtend
|
||||
{
|
||||
/**
|
||||
* 深度拷贝到指定目录
|
||||
* @param string $frdir 来源目录
|
||||
* @param string $todir 目标目录
|
||||
* @param array $files 指定文件
|
||||
* @param boolean $force 强制替换
|
||||
* @param boolean $remove 删除文件
|
||||
* @return boolean
|
||||
*/
|
||||
public static function copyfile(string $frdir, string $todir, array $files = [], bool $force = true, bool $remove = true): bool
|
||||
{
|
||||
$frdir = rtrim($frdir, '\\/') . DIRECTORY_SEPARATOR;
|
||||
$todir = rtrim($todir, '\\/') . DIRECTORY_SEPARATOR;
|
||||
// 扫描目录文件
|
||||
if (empty($files) && is_dir($frdir)) {
|
||||
$files = static::findFilesArray($frdir, null, function (SplFileInfo $info) {
|
||||
return $info->getBasename()[0] !== '.';
|
||||
});
|
||||
}
|
||||
// 复制文件列表
|
||||
foreach ($files as $target) {
|
||||
[$fromPath, $destPath] = [$frdir . $target, $todir . $target];
|
||||
if ($force || !is_file($destPath)) {
|
||||
is_dir($dir = dirname($destPath)) || mkdir($dir, 0777, true);
|
||||
copy($fromPath, $destPath);
|
||||
}
|
||||
// 删除来源文件
|
||||
$remove && unlink($fromPath);
|
||||
}
|
||||
// 删除来源目录
|
||||
$remove && static::removeEmptyDirectory($frdir);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除清空目录
|
||||
* @param string $path
|
||||
* @return boolean
|
||||
*/
|
||||
public static function removeEmptyDirectory(string $path): bool
|
||||
{
|
||||
$dirs = [$path];
|
||||
iterator_to_array(self::findFilesYield($path, null, function (SplFileInfo $file) use (&$dirs) {
|
||||
$file->isDir() ? $dirs[] = $file->getPathname() : unlink($file->getPathname());
|
||||
}));
|
||||
usort($dirs, function ($a, $b) {
|
||||
return strlen($b) <=> strlen($a);
|
||||
});
|
||||
foreach ($dirs as $dir) rmdir($dir);
|
||||
return !file_exists($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* 扫描目录列表
|
||||
* 扫描目录下的文件列表
|
||||
* @param string $path 扫描目录
|
||||
* @param ?integer $depth 扫描深度
|
||||
* @param string $filterExt 筛选后缀
|
||||
* @param boolean $shortPath 相对路径
|
||||
* @param string $ext 筛选后缀
|
||||
* @param boolean $short 相对路径
|
||||
* @return array
|
||||
*/
|
||||
public static function scanDirectory(string $path, ?int $depth = null, string $filterExt = '', bool $shortPath = true): array
|
||||
public static function scan(string $path, ?int $depth = null, string $ext = '', bool $short = true): array
|
||||
{
|
||||
return static::findFilesArray($path, $depth, function (SplFileInfo $info) use ($filterExt, &$files) {
|
||||
return $info->isDir() || $filterExt === '' || strtolower($info->getExtension()) === strtolower($filterExt);
|
||||
}, $shortPath);
|
||||
return static::find($path, $depth, function (SplFileInfo $info) use ($ext) {
|
||||
return $info->isDir() || $ext === '' || strtolower($info->getExtension()) === strtolower($ext);
|
||||
}, $short);
|
||||
}
|
||||
|
||||
/**
|
||||
* 扫描指定目录并返回文件路径数组
|
||||
* 扫描目录并返回文件路径数组
|
||||
* @param string $path 扫描目录
|
||||
* @param ?integer $depth 扫描深度
|
||||
* @param ?Closure $filter 文件过滤,返回 false 表示放弃
|
||||
* @param boolean $short 是否返回相对于给定路径的短路径
|
||||
* @return array 包含文件路径的数组
|
||||
*/
|
||||
public static function findFilesArray(string $path, ?int $depth = null, ?Closure $filter = null, bool $short = true): array
|
||||
public static function find(string $path, ?int $depth = null, ?Closure $filter = null, bool $short = true): array
|
||||
{
|
||||
[$info, $files] = [new SplFileInfo($path), []];
|
||||
if ($info->isDir() || $info->isFile()) {
|
||||
@ -119,6 +69,82 @@ class ToolsExtend
|
||||
return $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* 深度拷贝到指定目录
|
||||
* @param string $frdir 来源目录
|
||||
* @param string $todir 目标目录
|
||||
* @param array $files 指定文件
|
||||
* @param boolean $force 强制替换
|
||||
* @param boolean $remove 删除文件
|
||||
* @return boolean
|
||||
*/
|
||||
public static function copy(string $frdir, string $todir, array $files = [], bool $force = true, bool $remove = true): bool
|
||||
{
|
||||
$frdir = rtrim($frdir, '\\/') . DIRECTORY_SEPARATOR;
|
||||
$todir = rtrim($todir, '\\/') . DIRECTORY_SEPARATOR;
|
||||
// 扫描目录文件
|
||||
if (empty($files) && is_dir($frdir)) {
|
||||
$files = static::find($frdir, null, function (SplFileInfo $info) {
|
||||
return $info->getBasename()[0] !== '.';
|
||||
});
|
||||
}
|
||||
// 复制文件列表
|
||||
foreach ($files as $target) {
|
||||
[$fromPath, $destPath] = [$frdir . $target, $todir . $target];
|
||||
if ($force || !is_file($destPath)) {
|
||||
is_dir($dir = dirname($destPath)) || mkdir($dir, 0777, true);
|
||||
copy($fromPath, $destPath);
|
||||
}
|
||||
// 删除来源文件
|
||||
$remove && unlink($fromPath);
|
||||
}
|
||||
// 删除来源目录
|
||||
$remove && static::remove($frdir);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除清空目录
|
||||
* @param string $path
|
||||
* @return boolean
|
||||
*/
|
||||
public static function remove(string $path): bool
|
||||
{
|
||||
if (!file_exists($path)) return true;
|
||||
if (is_file($path)) return unlink($path);
|
||||
$dirs = [$path];
|
||||
iterator_to_array(self::findFilesYield($path, null, function (SplFileInfo $file) use (&$dirs) {
|
||||
$file->isDir() ? $dirs[] = $file->getPathname() : unlink($file->getPathname());
|
||||
}));
|
||||
usort($dirs, function ($a, $b) {
|
||||
return strlen($b) <=> strlen($a);
|
||||
});
|
||||
foreach ($dirs as $dir) file_exists($dir) && is_dir($dir) && rmdir($dir);
|
||||
return !file_exists($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* 兼容旧方式调用
|
||||
* @param string $method
|
||||
* @param array $arguments
|
||||
* @return array|bool
|
||||
* @throws \think\admin\Exception
|
||||
*/
|
||||
public static function __callStatic(string $method, array $arguments)
|
||||
{
|
||||
$methods = [
|
||||
'copyfile' => 'copy',
|
||||
'scandirectory' => 'scan',
|
||||
'findfilesarray' => 'find',
|
||||
'removeemptydirectory' => 'remove',
|
||||
];
|
||||
if ($real = $methods[strtolower($method)] ?? null) {
|
||||
return self::{$real}(...$arguments);
|
||||
} else {
|
||||
throw new Exception("method not exists: ToolsExtend::{$method}()");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归扫描指定目录,返回文件或目录的 SplFileInfo 对象。
|
||||
* @param string $path 目录路径。
|
||||
@ -130,15 +156,14 @@ class ToolsExtend
|
||||
*/
|
||||
private static function findFilesYield(string $path, ?int $depth = null, ?Closure $filter = null, bool $appendPath = false, int $currDepth = 1): Generator
|
||||
{
|
||||
if (file_exists($path) && is_dir($path) && (!is_numeric($depth) || $currDepth <= $depth)) {
|
||||
if (file_exists($path) && is_dir($path) && (is_null($depth) || $currDepth <= $depth)) {
|
||||
foreach (new FilesystemIterator($path, FilesystemIterator::SKIP_DOTS) as $item) {
|
||||
if ($filter === null || $filter($item) !== false) {
|
||||
if ($item->isDir() && !$item->isLink()) {
|
||||
$appendPath && yield $item;
|
||||
yield from static::findFilesYield($item->getPathname(), $depth, $filter, $appendPath, $currDepth + 1);
|
||||
} else {
|
||||
yield $item;
|
||||
}
|
||||
if ($filter !== null && $filter($item) === false) continue;
|
||||
if ($item->isDir() && !$item->isLink()) {
|
||||
$appendPath && yield $item;
|
||||
yield from static::findFilesYield($item->getPathname(), $depth, $filter, $appendPath, $currDepth + 1);
|
||||
} else {
|
||||
yield $item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -119,7 +119,7 @@ class NodeService extends Service
|
||||
$ignoreMethods = get_class_methods('\think\admin\Controller');
|
||||
$ignoreAppNames = Library::$sapp->config->get('app.rbac_ignore', []);
|
||||
// 扫描所有代码控制器节点,更新节点缓存
|
||||
foreach (ToolsExtend::scanDirectory(Library::$sapp->getBasePath(), null, 'php') as $name) {
|
||||
foreach (ToolsExtend::scan(Library::$sapp->getBasePath(), null, 'php') as $name) {
|
||||
if (preg_match("|^(\w+)/controller/(.+)\.php$|i", strtr($name, '\\', '/'), $matches)) {
|
||||
[, $appName, $className] = $matches;
|
||||
if (in_array($appName, $ignoreAppNames)) continue;
|
||||
@ -130,7 +130,7 @@ class NodeService extends Service
|
||||
foreach (Plugin::get() as $appName => $plugin) {
|
||||
if (in_array($appName, $ignoreAppNames)) continue;
|
||||
[$appPath, $appSpace] = [$plugin['path'], $plugin['space']];
|
||||
foreach (ToolsExtend::scanDirectory($appPath, null, 'php') as $name) {
|
||||
foreach (ToolsExtend::scan($appPath, null, 'php') as $name) {
|
||||
if (preg_match("|^.*?controller/(.+)\.php$|i", strtr($name, '\\', '/'), $matches)) {
|
||||
static::_parseClass($appName, $appSpace, $matches[1], $ignoreMethods, $data);
|
||||
}
|
||||
@ -208,7 +208,7 @@ class NodeService extends Service
|
||||
public static function __callStatic(string $name, array $arguments)
|
||||
{
|
||||
if ($name === 'scanDirectory') {
|
||||
return ToolsExtend::scanDirectory(...$arguments);
|
||||
return ToolsExtend::scan(...$arguments);
|
||||
} elseif ($name === 'getModules') {
|
||||
return ModuleService::getModules(...$arguments);
|
||||
} else {
|
||||
|
||||
@ -87,15 +87,15 @@ class Publish extends Command
|
||||
{
|
||||
// 复制系统配置文件
|
||||
$frdir = rtrim($copy, '\\/') . DIRECTORY_SEPARATOR . 'config';
|
||||
ToolsExtend::copyfile($frdir, syspath('config'), [], $force, false);
|
||||
ToolsExtend::copy($frdir, syspath('config'), [], $force, false);
|
||||
|
||||
// 复制静态资料文件
|
||||
$frdir = rtrim($copy, '\\/') . DIRECTORY_SEPARATOR . 'public';
|
||||
ToolsExtend::copyfile($frdir, syspath('public'), [], true, false);
|
||||
ToolsExtend::copy($frdir, syspath('public'), [], true, false);
|
||||
|
||||
// 复制数据库脚本
|
||||
$frdir = rtrim($copy, '\\/') . DIRECTORY_SEPARATOR . 'database';
|
||||
ToolsExtend::copyfile($frdir, syspath('database/migrations'), [], $force, false);
|
||||
ToolsExtend::copy($frdir, syspath('database/migrations'), [], $force, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -169,7 +169,7 @@ class MultAccess
|
||||
// 加载应用函数文件
|
||||
if (is_file($file = "{$appPath}common{$ext}")) include_once $file;
|
||||
// 加载应用配置文件
|
||||
ToolsExtend::findFilesArray($appPath . 'config', 1, function (SplFileInfo $info) use ($ext) {
|
||||
ToolsExtend::find($appPath . 'config', 1, function (SplFileInfo $info) use ($ext) {
|
||||
if ($info->isFile() && strtolower(".{$info->getExtension()}") === $ext) {
|
||||
$this->app->config->load($info->getPathname(), $info->getBasename($ext));
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user