Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/think/Console.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
use think\console\command\make\Subscribe;
use think\console\command\make\Validate;
use think\console\command\optimize\Config;
use think\console\command\optimize\Optimize;
use think\console\command\optimize\Route;
use think\console\command\optimize\Schema;
use think\console\command\RouteList;
Expand Down Expand Up @@ -70,6 +71,7 @@ class Console
'make:listener' => Listener::class,
'make:service' => Service::class,
'make:subscribe' => Subscribe::class,
'optimize' => Optimize::class,
'optimize:config' => Config::class,
'optimize:route' => Route::class,
'optimize:schema' => Schema::class,
Expand Down Expand Up @@ -785,5 +787,4 @@ private function extractAllNamespaces(string $name): array

return $namespaces;
}

}
32 changes: 32 additions & 0 deletions src/think/console/command/CommandCallable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2025 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: yunwuxin <[email protected]>
// +----------------------------------------------------------------------

namespace think\console\command;

use think\console\Command;
use think\console\Input;

/**
* @mixin Command
*/
trait CommandCallable
{
/**
* @param class-string<Command> $class
*/
private function callCommand(string $class): Command
{
return tap(app($class, newInstance: true), function ($command) {
$command->setApp($this->app);
$command->run(new Input([]), clone $this->output);
});
}
}
71 changes: 45 additions & 26 deletions src/think/console/command/optimize/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,17 @@
// +----------------------------------------------------------------------
namespace think\console\command\optimize;

use InvalidArgumentException;
use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\Output;
use Throwable;

class Config extends Command
{
use Discoverable;

protected function configure()
{
$this->setName('optimize:config')
Expand All @@ -26,39 +30,54 @@ protected function configure()

protected function execute(Input $input, Output $output)
{
// 加载配置文件
$dir = $input->getArgument('dir') ?: '';
$path = $this->app->getRootPath() . 'runtime' . DIRECTORY_SEPARATOR . ($dir ? $dir . DIRECTORY_SEPARATOR : '');
if (!is_dir($path)) {
$dirs = ((array) $input->getArgument('dir')) ?: $this->getDefaultDirs();

foreach ($dirs as $dir) {
$path = $this->app->getRootPath() . 'runtime' . DIRECTORY_SEPARATOR . ($dir ? $dir . DIRECTORY_SEPARATOR : '');
try {
mkdir($path, 0755, true);
} catch (\Exception $e) {
// 创建失败
$cache = $this->buildCache($dir);
if (! is_dir($path)) {
mkdir($path, 0755, true);
}
file_put_contents($path . 'config.php', $cache);
} catch (Throwable $e) {
$output->warning($e->getMessage());
}
}
$file = $path . 'config.php';
$config = $this->loadConfig($dir);
$content = '<?php ' . PHP_EOL . 'return ' . var_export($config, true) . ';';
if (file_put_contents($file, $content)) {
$output->writeln("<info>Succeed!</info>");
} else {
$output->writeln("<error>config build fail</error>");
}

$output->info('Succeed!');
}

public function loadConfig($dir = '')
private function buildCache(?string $dir = null): string
{
$configPath = $this->app->getRootPath() . ($dir ? 'app' . DIRECTORY_SEPARATOR . $dir . DIRECTORY_SEPARATOR : '') . 'config' . DIRECTORY_SEPARATOR;
$files = [];

if (is_dir($configPath)) {
$files = glob($configPath . '*' . $this->app->getConfigExt());
$path = $this->app->getRootPath() . ($dir ? 'app' . DIRECTORY_SEPARATOR . $dir . DIRECTORY_SEPARATOR : '') . 'config' . DIRECTORY_SEPARATOR;
if (! is_dir($path)) {
throw new InvalidArgumentException("{$path} directory does not exist");
}

foreach ($files as $file) {
$this->app->config->load($file, pathinfo($file, PATHINFO_FILENAME));
// 使用 clone 防止多应用配置污染
$config = clone $this->app->config;
if (is_dir($path)) {
$files = glob($path . '*' . $this->app->getConfigExt());
foreach ($files as $file) {
$config->load($file, pathinfo($file, PATHINFO_FILENAME));
}
}

return $this->app->config->get();
}
}
return '<?php ' . PHP_EOL . 'return ' . var_export($config->get(), true) . ';';
}

/**
* 获取默认目录名
* @return array<int, ?string>
*/
private function getDefaultDirs(): array
{
// 包含全局应用配置目录
$dirs = [null];
if ($this->isInstalledMultiApp()) {
$dirs = array_merge($dirs, $this->discoveryMultiAppDirs('config'));
}
return $dirs;
}
}
44 changes: 44 additions & 0 deletions src/think/console/command/optimize/Discoverable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: yunwuxin <[email protected]>
// +----------------------------------------------------------------------
namespace think\console\command\optimize;

use Composer\InstalledVersions;
use DirectoryIterator;

trait Discoverable
{
/**
* 判断是否安装 topthink/think-multi-app
*/
private function isInstalledMultiApp(): bool
{
return InstalledVersions::isInstalled('topthink/think-multi-app');
}

/**
* 发现多应用程序目录
* @return string[]
*/
private function discoveryMultiAppDirs(string $directoryName): array
{
$dirs = [];
foreach (new DirectoryIterator($this->app->getAppPath()) as $item) {
if (! $item->isDir() || $item->isDot()) {
continue;
}
$path = $item->getRealPath() . DIRECTORY_SEPARATOR . $directoryName . DIRECTORY_SEPARATOR;
if (is_dir($path)) {
$dirs[] = $item->getFilename();
}
}
return $dirs;
}
}
40 changes: 40 additions & 0 deletions src/think/console/command/optimize/Optimize.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <[email protected]>
// +----------------------------------------------------------------------
namespace think\console\command\optimize;

use think\console\Command;
use think\console\command\CommandCallable;
use think\console\Input;
use think\console\Output;

class Optimize extends Command
{
use CommandCallable;

protected function configure()
{
$this->setName('optimize')
->setDescription('Build cache.');
}

protected function execute(Input $input, Output $output)
{
$commands = [
Config::class,
Route::class,
Schema::class,
];
foreach ($commands as $class) {
$command = $this->callCommand($class);
$this->output->info($command->getName() . ' run succeed!');
}
}
}
42 changes: 33 additions & 9 deletions src/think/console/command/optimize/Route.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,18 @@
namespace think\console\command\optimize;

use DirectoryIterator;
use InvalidArgumentException;
use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\Output;
use think\event\RouteLoaded;
use Throwable;

class Route extends Command
{
use Discoverable;

protected function configure()
{
$this->setName('optimize:route')
Expand All @@ -28,18 +32,22 @@ protected function configure()

protected function execute(Input $input, Output $output)
{
$dir = $input->getArgument('dir') ?: '';
$dirs = ((array) $input->getArgument('dir')) ?: $this->getDefaultDirs();

$path = $this->app->getRootPath() . 'runtime' . DIRECTORY_SEPARATOR . ($dir ? $dir . DIRECTORY_SEPARATOR : '');
if (!is_dir($path)) {
foreach ($dirs as $dir) {
$path = $this->app->getRootPath() . 'runtime' . DIRECTORY_SEPARATOR . ($dir ? $dir . DIRECTORY_SEPARATOR : '');
try {
mkdir($path, 0755, true);
} catch (\Exception $e) {
// 创建失败
$cache = $this->buildRouteCache($dir);
if (! is_dir($path)) {
mkdir($path, 0755, true);
}
file_put_contents($path . 'route.php', $cache);
} catch (Throwable $e) {
$output->warning($e->getMessage());
}
}
file_put_contents($path . 'route.php', $this->buildRouteCache($dir));
$output->writeln('<info>Succeed!</info>');

$output->info('Succeed!');
}

protected function scanRoute($path, $root, $autoGroup)
Expand All @@ -53,7 +61,7 @@ protected function scanRoute($path, $root, $autoGroup)
if ($fileinfo->getType() == 'file' && $fileinfo->getExtension() == 'php') {
$groupName = str_replace('\\', '/', substr_replace($fileinfo->getPath(), '', 0, strlen($root)));
if ($groupName) {
$this->app->route->group($groupName, function() use ($fileinfo) {
$this->app->route->group($groupName, function () use ($fileinfo) {
include $fileinfo->getRealPath();
});
} else {
Expand All @@ -73,6 +81,9 @@ protected function buildRouteCache(?string $dir = null): string
// 路由检测
$autoGroup = $this->app->route->config('route_auto_group');
$path = $this->app->getRootPath() . ($dir ? 'app' . DIRECTORY_SEPARATOR . $dir . DIRECTORY_SEPARATOR : '') . 'route' . DIRECTORY_SEPARATOR;
if (! is_dir($path)) {
throw new InvalidArgumentException("{$path} directory does not exist");
}

$this->scanRoute($path, $path, $autoGroup);

Expand All @@ -83,4 +94,17 @@ protected function buildRouteCache(?string $dir = null): string
return '<?php ' . PHP_EOL . 'return ' . var_export($rules, true) . ';';
}

/**
* 获取默认目录名
* @return array<int, ?string>
*/
private function getDefaultDirs(): array
{
// 判断是否使用多应用模式
// 如果使用了则扫描 app 目录
// 否则返回 null,让其扫描根目录的 route 目录
return $this->isInstalledMultiApp()
? $this->discoveryMultiAppDirs('route')
: [null];
}
}
Loading