feat: 公共表更名 common/member 前缀 + 插件命令自动加载 + 版本 1.1.1

- 18 张公共表更名(addon/attachment/configure/links/spider_log/spider_stat/sms/notice/ad/task/prop/medal/help/card -> common_*,member_wallets->member_wallet,score_rule/score_log -> member_*,addon_config->common_addonconf),模型全部对齐新表名,Db 直引用清零
- Attachment 模型补  表名绑定,修复富文本上传查 wxapp_attachment 1146 隐患
- install.sql + 迁移 SQL:backend_admin/backend_role delete_at 默认 0,修复软删除(NULL != 0)误过滤导致后台菜单为空
- AppService::boot() 支持插件 info.php 声明 commands 自动注册插件命令(psr-4 自动加载,坏类名自动跳过)
- 各插件(haonav/mqttbroker/wxchat/articles/blog/forum 等)字段与配置同步调整
- 框架版本 1.1.0 -> 1.1.1
This commit is contained in:
ywxapp
2026-08-20 20:19:15 +08:00
parent 303f548664
commit 1d49e6f5ee
395 changed files with 13342 additions and 2012 deletions
+14 -8
View File
@@ -372,15 +372,21 @@ class AddonHealth extends Command
Cache::delete($testKey);
// 插件缓存命中情况(仅警告,不影响健康)
$addon = Config::get('addon', []);
foreach ($addon as $addon) {
if (!isset($addon['name']) || !($addon['state'] ?? false)) {
continue;
}
if (Cache::get('addon_config_' . $addon['name']) === false) {
$result['warnings'][] = "插件 {$addon['name']} 缓存未命中,可能影响性能";
// 插件缓存命中情况(仅警告,不影响健康)。
// 注意:Config::get('addon') 是框架 addon 组件配置(multi_app/priority 等),非插件列表;
// 直接用 AddonModel 的插件名列表,避免遍历配置时访问 true['name']。
try {
$addons = \ywxapp\model\AddonModel::field('name,state')->select()->toArray();
foreach ($addons as $addon) {
if (!isset($addon['name']) || !($addon['state'] ?? false)) {
continue;
}
if (Cache::get('addon_config_' . $addon['name']) === false) {
$result['warnings'][] = "插件 {$addon['name']} 缓存未命中,可能影响性能";
}
}
} catch (\Throwable $e) {
// 数据表可能尚未创建,忽略
}
} catch (\Exception $e) {
$result['healthy'] = false;
+32 -9
View File
@@ -53,7 +53,7 @@ class AddonMake extends Make
$this->setName('addon:make')
->addArgument('addon', Argument::OPTIONAL, 'addon name, e.g. demo (required for build & generators)')
->addOption('action', 'a', Option::VALUE_REQUIRED, 'build|clear|controller|model|middleware|validate|event|listener|service|subscribe')
->addOption('name', 'n', Option::VALUE_OPTIONAL, 'class name for generator actions, e.g. User')
->addOption('name', null, Option::VALUE_OPTIONAL, 'class name for generator actions, e.g. User')
->addOption('api', null, Option::VALUE_NONE, 'controller: generate an api controller class.')
->addOption('plain', null, Option::VALUE_NONE, 'controller: generate an empty controller class.')
->addOption('cache', 'c', Option::VALUE_NONE, 'clear: clear cache file')
@@ -62,7 +62,7 @@ class AddonMake extends Make
->setDescription('Unified addon scaffold & class generator (build / clear / controller / model / middleware / validate / event / listener / service / subscribe)');
}
protected function execute(Input $input, Output $output): int
{
$addon = trim((string) $input->getArgument('addon'));
@@ -227,8 +227,12 @@ class AddonMake extends Make
mkdir($appPath . 'controller');
mkdir($appPath . 'controller/backend');
mkdir($appPath . 'controller/member');
mkdir($appPath . 'controller/api');
}
$this->buildIndexController($app, $namespace);
$this->buildIndexController($app, $namespace); // 前台 FrontendBase
$this->buildIndexController($app, $namespace, 'backend'); // BackendBase
$this->buildIndexController($app, $namespace, 'member'); // MemberBase
$this->buildIndexController($app, $namespace, 'api'); // ApiBase
if (! is_dir($appPath . 'lang')) {
mkdir($appPath . 'lang');
}
@@ -342,14 +346,25 @@ class AddonMake extends Make
* @param string $namespace 类库命名空间
* @return void
*/
public function buildIndexController(string $app, string $namespace): void
public function buildIndexController(string $app, string $namespace, string $area = ''): void
{
$suffix = $this->app->config->get('route.controller_suffix') ? 'Controller' : '';
$filename = $this->basePath . ($app ? $app . DIRECTORY_SEPARATOR : '') . 'controller' . DIRECTORY_SEPARATOR . 'Index' . $suffix . '.php';
$dir = 'controller' . ($area !== '' ? DIRECTORY_SEPARATOR . $area : '');
$filename = $this->basePath . ($app ? $app . DIRECTORY_SEPARATOR : '') . $dir . DIRECTORY_SEPARATOR . 'Index' . $suffix . '.php';
if (! is_file($filename)) {
$content = file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'addon' . DIRECTORY_SEPARATOR . 'controller.stub');
$content = str_replace(['{%className%}', '{%actionSuffix%}', '{%namespace%}', '{%app_namespace%}'], ['Index', $suffix, $namespace . '\\controller', $namespace], $content);
$base_class = $area == 'backend' ? 'BackendBase' : ($area == 'member' ? 'MemberBase' : ($area == 'api' ? 'ApiBase' : 'FrontendBase'));
$content = file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'addon' . DIRECTORY_SEPARATOR . 'controller.stub');
$content = str_replace(
[
'{%className%}',
'{%actionSuffix%}',
'{%namespace%}',
'{%app_namespace%}',
'{%baseClass%}'
],
['Index', $suffix, $namespace . ($area !== '' ? '\\controller\\' . $area : '\\controller'), $namespace, $base_class],
$content
);
$this->checkDirBuild(dirname($filename));
file_put_contents($filename, $content);
}
@@ -366,8 +381,16 @@ class AddonMake extends Make
{
$filename = $this->basePath . ($app ? $app . DIRECTORY_SEPARATOR : '') . 'route' . DIRECTORY_SEPARATOR . 'app.php';
if (! is_file($filename)) {
$content = file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'addon' . DIRECTORY_SEPARATOR . 'route.stub');
$content = str_replace(
[
'{%app%}'
],
[$app],
$content
);
$this->checkDirBuild(dirname($filename));
file_put_contents($filename, "<?php" . PHP_EOL . "use think\\facade\\Route;" . PHP_EOL . PHP_EOL);
file_put_contents($filename, $content);
}
}
+8 -1
View File
@@ -19,6 +19,7 @@ use think\File;
use ywxapp\exception\AddonException;
use ywxapp\service\AddonService;
use ywxapp\service\AddonHotReload;
use think\facade\Env;
/**
* 插件统一管理命令(合并 develop / install / reload)
@@ -94,8 +95,14 @@ class AddonManage extends Command
} catch (AddonException $e) {
$output->writeln('<error>' . $e->getMessage() . '</error>');
return 1;
} catch (\Exception $e) {
} catch (\Throwable $e) {
// \Throwable 兜底:\Error(如类型错误)不是 \Exception 子类,必须单独捕获,
// 否则会漏到框架层导致无友好提示。
$output->writeln('<error>开发模式安装失败:' . $e->getMessage() . '</error>');
if (Env::get('app_debug')) {
$output->writeln('<error>FILE: ' . $e->getFile() . ':' . $e->getLine() . '</error>');
$output->writeln('<error>TRACE: ' . $e->getTraceAsString() . '</error>');
}
return 1;
}
return 0;
+15 -11
View File
@@ -26,7 +26,7 @@ use ywxapp\model\BaseModel;
* 整合以下自愈能力,使一个出问题的插件恢复到「菜单正确 + 表结构完整 + 配置齐全」的状态:
* 1. 重载菜单:refreshMenu()(清旧 admin_power/user_rule + 重建,顺带修复菜单路由前缀)
* 2. 数据库自愈:解析 install.sql 中该插件全部 CREATE TABLE,缺表建表、缺列补列
* 3. 配置行补全:确保 addon_config 表存在该插件配置行(无则按默认 info 写入)
* 3. 配置行补全:确保 common_addonconf 表存在该插件配置行(无则按默认 info 写入)
*
* 用法:
* php think addon:repair <插件名> # 修复指定插件(菜单 + 表 + 配置)
@@ -245,24 +245,25 @@ class AddonRepair extends Command
}
/**
* 配置行补全:确保 addon_config 表有该插件配置行。
* 配置行补全:确保 common_addonconf 表有该插件配置行。
*/
private function repairConfig(AddonService $svc, string $name, Output $output): bool
{
$default = Config::get('database.default');
$prefix = Config::get("database.connections.{$default}.prefix") ?: '';
$configTable = $prefix . 'addon_config';
$configTable = $prefix . 'common_addonconf';
try {
if (!BaseModel::tableExists($configTable)) {
$output->writeln('<comment>[配置] addon_config 表不存在,跳过</comment>');
$output->writeln('<comment>[配置] common_addonconf 表不存在,跳过</comment>');
return true;
}
$row = Db::table($configTable)->where('name', $name)->find();
if (!empty($row)) {
// common_addonconf 设计:每行一个配置项(addon + name 唯一),故按 addon 判断是否存在
$existing = Db::table($configTable)->where('addon', $name)->count();
if ($existing > 0) {
$output->writeln('<comment>[配置] 配置行已存在,跳过</comment>');
return true;
}
// 读取插件默认配置(config.php 返回数组)
// 读取插件默认配置(config.php 返回关联数组 name=>value)
$configFile = $this->addonDir($name) . 'config.php';
$value = [];
if (is_file($configFile)) {
@@ -271,10 +272,13 @@ class AddonRepair extends Command
$value = $cfg;
}
}
$data = [
'name' => $name,
'value' => json_encode($value, JSON_UNESCAPED_UNICODE),
];
if (empty($value)) {
$output->writeln('<comment>[配置] 无默认配置,跳过</comment>');
return true;
}
// 逐配置项写入独立行(与 AddonService::config/$changed 的存储格式一致)
\ywxapp\service\AddonService::config($name, $value);
$data = []; // 已通过 AddonService::config 写入,无需再 insert
// 兼容不同时间戳字段名(createtime/updatetime 或 create_time/update_time)
$cols = Db::query("SHOW COLUMNS FROM `{$configTable}`");
$colNames = array_column($cols, 'Field');
+70 -253
View File
@@ -17,6 +17,8 @@ use think\console\Output;
use think\console\input\Argument;
use think\console\input\Option;
use think\console\command\Make;
/**
* AppCommand 应用命令统一入口
*
@@ -44,25 +46,8 @@ use think\console\input\Option;
* php think app clear --cache # 清理缓存
* php think app build myapp # 构建应用目录
*/
class AppCommand extends Command
{
/**
* Make 型子命令配置
* type : 类型标签(用于成功/存在提示)
* stub : stub 文件名(不含 .stub 扩展)
* ns : 命名空间末尾段(如 controller/model/event ...)
* suffix : 类名后缀(仅 controller 在开启 controller_suffix 时追加 Controller)
*/
private const MAKE_TYPES = [
'controller' => ['type' => 'Controller', 'stub' => 'controller', 'ns' => 'controller', 'suffix' => 'Controller'],
'model' => ['type' => 'Model', 'stub' => 'model', 'ns' => 'model', 'suffix' => ''],
'event' => ['type' => 'Event', 'stub' => 'event', 'ns' => 'event', 'suffix' => ''],
'listener' => ['type' => 'Listener', 'stub' => 'listener', 'ns' => 'listener', 'suffix' => ''],
'middleware' => ['type' => 'Middleware', 'stub' => 'middleware', 'ns' => 'middleware', 'suffix' => ''],
'service' => ['type' => 'Service', 'stub' => 'service', 'ns' => 'service', 'suffix' => ''],
'subscribe' => ['type' => 'Subscribe', 'stub' => 'subscribe', 'ns' => 'subscribe', 'suffix' => ''],
'validate' => ['type' => 'Validate', 'stub' => 'validate', 'ns' => 'validate', 'suffix' => ''],
];
class AppCommand extends Make
{
/**
* 应用基础目录(Build 使用)
@@ -70,12 +55,43 @@ class AppCommand extends Command
*/
private $basePath = '';
/**
* stub 模板目录(已从 ywxapp/command/app/stubs 上移至此)
*/
private function stubDir(): string
private $subCommon = '';
protected function getStub(): string
{
return __DIR__ . DIRECTORY_SEPARATOR . 'app' . DIRECTORY_SEPARATOR;
if ($this->input->getOption('api')) {
return __DIR__ . DIRECTORY_SEPARATOR . 'appstubs' . DIRECTORY_SEPARATOR . $this->subCommon . '.api.stub';
}
if ($this->input->getOption('plain')) {
return __DIR__ . DIRECTORY_SEPARATOR . 'appstubs' . DIRECTORY_SEPARATOR . $this->subCommon . '.plain.stub';
}
return __DIR__ . DIRECTORY_SEPARATOR . 'appstubs' . DIRECTORY_SEPARATOR . $this->subCommon . '.stub';
}
protected function getNamespace(string $app): string
{
if ($this->subCommon === 'model') {
return 'ywxapp\\model';
}
return parent::getNamespace($app) . '\\' . $this->subCommon;
}
protected function getClassName(string $name): string
{
if ($this->subCommon == 'controller') {
return parent::getClassName($name) . ($this->app->config->get('route.controller_suffix') ? 'Controller' : '');
}
return parent::getClassName($name);
}
protected function getPathName(string $name): string
{
if ($this->subCommon == 'model') {
$name = substr($name, 6);
return $this->app->getRootPath() . 'ywxapp' . '/' . ltrim(str_replace('\\', '/', $name), '/') . '.php';
}
$name = substr($name, 4);
return $this->app->getBasePath() . ltrim(str_replace('\\', '/', $name), '/') . '.php';
}
/**
@@ -98,171 +114,42 @@ class AppCommand extends Command
/**
* 执行命令
*/
protected function execute(Input $input, Output $output): int
protected function execute(Input $input, Output $output)
{
if ($input->getOption('list') || empty($input->getArgument('subcommand'))) {
$this->showList($output);
return 0;
}
$sub = $input->getArgument('subcommand');
$name = (string) $input->getArgument('name');
if (isset(self::MAKE_TYPES[$sub])) {
return $this->runMake($sub, $name, $input, $output);
}
if ($sub === 'build') {
$this->subCommon = $input->getArgument('subcommand');
$name = trim($input->getArgument('name'));
if ($this->subCommon === 'build') {
return $this->runBuild($name, $output);
}
if ($sub === 'clear') {
if ($this->subCommon === 'clear') {
return $this->runClear($name, $input, $output);
}
$output->writeln('<error>未知子命令: ' . $sub . '</error>');
$this->showList($output);
return 1;
}
/**
* 列出所有可用子命令
*/
private function showList(Output $output): void
{
$output->writeln('<info>YwxApp 应用命令(`php think app <子命令> [参数]`):</info>');
$output->writeln('');
$width = max(array_map('strlen', array_keys(self::MAKE_TYPES + ['build' => 1, 'clear' => 1])));
foreach (array_keys(['build' => 1, 'clear' => 1] + self::MAKE_TYPES) as $name) {
$desc = [
'build' => '构建应用目录',
'clear' => '清理运行时文件',
'controller' => '生成控制器(--api/--plain)',
'model' => '生成模型',
'event' => '生成事件',
'listener' => '生成监听器',
'middleware' => '生成中间件',
'service' => '生成服务',
'subscribe' => '生成订阅器',
'validate' => '生成验证器',
][$name];
$output->writeln(' ' . str_pad($name, $width) . ' ' . $desc);
}
$output->writeln('');
$output->writeln('示例:php think app controller app\\index');
$output->writeln(' php think app clear --cache');
}
/* ===================== Make 型生成器 ===================== */
/**
* 运行 Make 型子命令
*/
private function runMake(string $type, string $name, Input $input, Output $output): int
{
if ($name === '') {
$output->writeln('<error>缺少类名参数,用法:php think app ' . $type . ' &lt;类名&gt;</error>');
return 1;
}
$cfg = self::MAKE_TYPES[$type];
$classname = $this->makeClassName($type, $name);
$pathname = $this->makePathName($classname);
$classname = $this->getClassName($name);
$pathname = $this->getPathName($classname);
if (is_file($pathname)) {
$output->writeln('<error>' . $cfg['type'] . ':' . $classname . ' already exists!</error>');
return 1;
$output->writeln('<error>' . $this->type . ':' . $classname . ' already exists!</error>');
return false;
}
if (!is_dir(dirname($pathname))) {
mkdir(dirname($pathname), 0755, true);
}
file_put_contents($pathname, $this->buildClass($classname, $type, $input));
$output->writeln('<info>' . $cfg['type'] . ':' . $classname . ' created successfully.</info>');
return 0;
file_put_contents($pathname, $this->buildClass($classname));
$output->writeln('<info>' . $this->type . ':' . $classname . ' created successfully.</info>');
}
/**
* 解析 stub 路径(controller 支持 --api/--plain)
*/
private function makeStub(string $type, Input $input): string
protected function buildClass(string $name)
{
if ($type === 'controller') {
if ($input->getOption('api')) {
return $this->stubDir() . 'controller.api.stub';
}
if ($input->getOption('plain')) {
return $this->stubDir() . 'controller.plain.stub';
}
return $this->stubDir() . 'controller.stub';
}
return $this->stubDir() . self::MAKE_TYPES[$type]['stub'] . '.stub';
}
/**
* 解析命名空间
*/
private function makeNamespace(string $type, string $app): string
{
return 'app' . ($app ? '\\' . $app : '') . '\\' . self::MAKE_TYPES[$type]['ns'];
}
/**
* 解析完整类名(等价于 think\console\command\Make::getClassName + Controller 后缀)
*/
private function makeClassName(string $type, string $name): string
{
if (str_contains($name, '\\')) {
$class = $name;
} else {
$app = '';
if (str_contains($name, '@')) {
[$app, $name] = explode('@', $name);
}
if (str_contains($name, '/')) {
$name = str_replace('/', '\\', $name);
}
$class = $this->makeNamespace($type, $app) . '\\' . $name;
}
$suffix = self::MAKE_TYPES[$type]['suffix'];
if ($suffix !== '' && $this->app->config->get('route.controller_suffix')) {
$class .= $suffix;
}
return $class;
}
/**
* 解析文件路径(等价于各 Make 命令重写的 getPathName)
*/
private function makePathName(string $name): string
{
return $this->app->getRootPath() . ltrim(str_replace('\\', '/', $name), '/') . '.php';
}
/**
* 用 stub 渲染类文件(等价于 think\console\command\Make::buildClass)
*/
private function buildClass(string $name, string $type, Input $input): string
{
$stub = file_get_contents($this->makeStub($type, $input));
$stub = file_get_contents($this->getStub());
$namespace = trim(implode('\\', array_slice(explode('\\', $name), 0, -1)), '\\');
$class = str_replace($namespace . '\\', '', $name);
return str_replace(
['{%className%}', '{%actionSuffix%}', '{%namespace%}', '{%app_namespace%}'],
[
$class,
$this->app->config->get('route.action_suffix'),
$namespace,
$this->app->getNamespace(),
],
$stub
);
$class = str_replace($namespace . '\\', '', $name);
return str_replace(['{%className%}', '{%actionSuffix%}', '{%namespace%}', '{%app_namespace%}'], [
$class,
$this->app->config->get('route.action_suffix'),
$namespace,
$this->app->getNamespace(),
], $stub);
}
/* ===================== Build 命令 ===================== */
@@ -273,18 +160,20 @@ class AppCommand extends Command
{
$this->basePath = $this->app->getRootPath() . 'app' . DIRECTORY_SEPARATOR;
$app = $app ?: '';
if (is_file($this->basePath . 'build.php')) {
$list = include $this->basePath . 'build.php';
} else {
$list = [
'__dir__' => ['controller', 'model', 'view'],
'__file__' => ['common.php', 'event.php', 'middleware.php', 'service.php'],
'__dir__' => ['controller', 'model', 'view', 'route'],
'controller' => ['Index'],
'model' => [],
'view' => ['index/index'],
'route' => ['app'],
];
}
$this->buildApp($app, $list);
$output->writeln('<info>Successed</info>');
return 0;
}
@@ -296,15 +185,8 @@ class AppCommand extends Command
if (!is_dir($this->basePath . $app)) {
mkdir($this->basePath . $app);
}
$appPath = $this->basePath . ($app ? $app . DIRECTORY_SEPARATOR : '');
$namespace = 'app' . ($app ? '\\' . $app : '');
$this->buildCommon($app);
$this->buildHello($app, $namespace);
$this->buildapp1($app, $namespace);
$this->buildInfo($app);
foreach ($list as $path => $file) {
if ('__dir__' == $path) {
foreach ($file as $dir) {
@@ -330,6 +212,9 @@ class AppCommand extends Command
}
$content = '<?php' . PHP_EOL . 'namespace ' . $space . ';' . PHP_EOL . PHP_EOL . 'class ' . $class . PHP_EOL . '{' . PHP_EOL . PHP_EOL . '}';
break;
case 'route':
$content = "<?php" . PHP_EOL . PHP_EOL . "use think\\facade\Route;";
break;
case 'model':
$content = '<?php' . PHP_EOL . 'namespace ' . $space . ';' . PHP_EOL . PHP_EOL . 'use think\Model;' . PHP_EOL . PHP_EOL . 'class ' . $class . ' extends Model' . PHP_EOL . '{' . PHP_EOL . PHP_EOL . '}';
break;
@@ -350,70 +235,7 @@ class AppCommand extends Command
}
}
/**
* 创建应用的欢迎页面
*/
private function buildHello(string $app, string $namespace): void
{
$suffix = $this->app->config->get('route.controller_suffix') ? 'Controller' : '';
$filename = $this->basePath . ($app ? $app . DIRECTORY_SEPARATOR : '') . 'controller' . DIRECTORY_SEPARATOR . 'Index' . $suffix . '.php';
if (!is_file($filename)) {
$content = file_get_contents($this->stubDir() . 'controller.stub');
$content = str_replace(
['{%className%}', '{%actionSuffix%}', '{%namespace%}', '{%app_namespace%}'],
['Index', $suffix, $namespace . '\\controller', $this->app->getNamespace()],
$content
);
$this->checkDirBuild(dirname($filename));
file_put_contents($filename, $content);
}
}
private function buildapp1(string $app, string $namespace): void
{
$appPath = $this->basePath . ($app ? $app . DIRECTORY_SEPARATOR : '');
if (!is_file($appPath . 'app.php')) {
$content = file_get_contents($this->stubDir() . 'app.stub');
$content = str_replace(['{%namespace%}', '{%app%}', '{%className%}'], [$namespace, $app, 'app'], $content);
file_put_contents($appPath . 'app.php', $content);
}
}
private function buildInfo(string $app): void
{
$appPath = $this->basePath . ($app ? $app . DIRECTORY_SEPARATOR : '');
if (!is_file($appPath . 'info.php')) {
$array = [
'name' => '',
'title' => '',
'intro' => '',
'author' => '',
'website' => '',
'version' => '1.0.0',
'state' => 1,
'url' => '',
'license' => '',
'licenseto' => 0,
];
$array = array_merge($array, ['name' => $app, 'url' => '/' . $app]);
$output = "<?php\n return " . var_export($array, true) . ";\n?>";
file_put_contents($appPath . 'info.php', $output);
}
}
/**
* 创建应用的公共文件
*/
private function buildCommon(string $app): void
{
$appPath = $this->basePath . ($app ? $app . DIRECTORY_SEPARATOR : '');
foreach (['event', 'middleware', 'common', 'config'] as $nm) {
if (!is_file($appPath . $nm . '.php')) {
file_put_contents($appPath . $nm . '.php', '<?php' . PHP_EOL . '// 这是系统自动生成的' . $nm . '定义文件' . PHP_EOL . 'return [' . PHP_EOL . PHP_EOL . '];' . PHP_EOL);
}
}
}
/**
* 创建目录
@@ -433,7 +255,6 @@ class AppCommand extends Command
private function runClear(string $app, Input $input, Output $output): int
{
$runtimePath = $this->app->getRootPath() . 'runtime' . DIRECTORY_SEPARATOR . ($app ? $app . DIRECTORY_SEPARATOR : '');
if ($input->getOption('cache')) {
$path = $runtimePath . 'cache';
} elseif ($input->getOption('log')) {
@@ -441,12 +262,9 @@ class AppCommand extends Command
} else {
$path = $runtimePath;
}
$rmdir = $input->getOption('dir') ? true : false;
$this->clearRuntime(rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR, $rmdir);
$output->writeln('<info>Clear Successed</info>');
return 0;
}
@@ -456,7 +274,6 @@ class AppCommand extends Command
private function clearRuntime(string $path, bool $rmdir): void
{
$files = is_dir($path) ? scandir($path) : [];
foreach ($files as $file) {
if ('.' != $file && '..' != $file && is_dir($path . $file)) {
array_map('unlink', glob($path . $file . DIRECTORY_SEPARATOR . '*.*'));
+3 -3
View File
@@ -5,7 +5,7 @@ namespace {%namespace%};
use think\Request;
class {%className%} extends \ywxapp\controller\AddonFrontend
class {%className%} extends \ywxapp\controller\{%baseClass%}
{
/**
* Summary of needLogin
@@ -33,7 +33,7 @@ class {%className%} extends \ywxapp\controller\AddonFrontend
*/
public function index{%actionSuffix%}()
{
return "这是一个{%app_namespace%} 插件应用";
return "这是一个{%app_namespace%} 插件应用控制器{%namespace%}";
}
/**
@@ -74,7 +74,7 @@ class {%className%} extends \ywxapp\controller\AddonFrontend
* @param int $id
* @return \think\Response
*/
public function edit{%actionSuffix%}($id)
public function edit{%actionSuffix%}($id = null)
{
//
}
+24
View File
@@ -0,0 +1,24 @@
<?php
use think\facade\Route;
// 公共前缀 /{%app%},同时设置默认命名空间为 addon\{%app%}\controller
// 后台 → addon\{%app%}\controller\backend\Index
Route::group('backend', function () {
Route::get('index/index', 'index/index')->name('{%app%}_backend_index');
})->namespace('addon\{%app%}\controller\backend');
// 用户中心 → addon\{%app%}\controller\member\Index
Route::group('member', function () {
Route::get('index/index', 'index/index')->name('{%app%}_member_index');
})->namespace('addon\{%app%}\controller\member');
// API → apaddonp\{%app%}\controller\api\Index
Route::group('api', function () {
Route::get('index/index', 'index/index')->name('{%app%}_api_index');
})->namespace('addon\{%app%}\controller\api');
// 前台 → addon\{%app%}\controller\Index(不加子分组)
Route::get('index/index', 'index/index')->name('{%app%}_index');