From dd676bdc0ccdf8234ceb4bedc4d05454e18aa556 Mon Sep 17 00:00:00 2001
From: mkm <727897186@qq.com>
Date: Wed, 14 Aug 2024 09:46:31 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20=E6=9B=B4=E6=96=B0=E4=BA=86MakePluginCo?=
 =?UTF-8?q?mmand=E7=B1=BB=E4=BB=A5=E6=94=AF=E6=8C=81=E6=9B=B4=E6=96=B0?=
 =?UTF-8?q?=E6=8F=92=E4=BB=B6=20feat:=20=E6=9B=B4=E6=96=B0=E4=BA=86MakeBoo?=
 =?UTF-8?q?tstrapCommand=E3=80=81MakeCommandCommand=E3=80=81MakeMiddleware?=
 =?UTF-8?q?Command=E5=92=8CMakeModelCommand=E7=B1=BB=E4=BB=A5=E6=94=AF?=
 =?UTF-8?q?=E6=8C=81=E8=A6=86=E7=9B=96=E5=B7=B2=E5=AD=98=E5=9C=A8=E7=9A=84?=
 =?UTF-8?q?=E6=96=87=E4=BB=B6=20feat:=20=E6=9B=B4=E6=96=B0=E4=BA=86App?=
 =?UTF-8?q?=E7=B1=BB=E4=BB=A5=E4=BF=AE=E5=A4=8D=E5=8F=AF=E8=83=BD=E7=9A=84?=
 =?UTF-8?q?=E8=B7=AF=E5=BE=84=E9=94=99=E8=AF=AF=20feat:=20=E6=9B=B4?=
 =?UTF-8?q?=E6=96=B0=E4=BA=86Db=E3=80=81Raw=E3=80=81ThinkPHP=E3=80=81Twig?=
 =?UTF-8?q?=E5=92=8CBlade=E7=B1=BB=E4=BB=A5=E6=94=AF=E6=8C=81=E5=9C=A8?=
 =?UTF-8?q?=E8=A7=86=E5=9B=BE=E6=B8=B2=E6=9F=93=E6=97=B6=E5=90=88=E5=B9=B6?=
 =?UTF-8?q?=E5=8F=98=E9=87=8F=20feat:=20=E6=9B=B4=E6=96=B0=E4=BA=86webman?=
 =?UTF-8?q?=E6=96=87=E4=BB=B6=E4=BB=A5=E6=94=AF=E6=8C=81=E5=9C=A8=E6=8F=92?=
 =?UTF-8?q?=E4=BB=B6=E4=B8=AD=E6=9F=A5=E6=89=BE=E5=91=BD=E4=BB=A4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 app/api/controller/order/CartController.php   | 14 +--
 composer.json                                 |  6 +-
 composer.lock                                 | 38 +++------
 support/helpers.php                           | 21 +++--
 vendor/composer/installed.json                | 40 +++------
 vendor/composer/installed.php                 | 12 +--
 .../src/Commands/AppPluginCreateCommand.php   | 85 +++++++++++++++++++
 .../src/Commands/AppPluginUpdateCommand.php   | 42 +++++++++
 .../src/Commands/MakeBootstrapCommand.php     | 13 ++-
 .../src/Commands/MakeCommandCommand.php       | 12 ++-
 .../src/Commands/MakeControllerCommand.php    | 14 ++-
 .../src/Commands/MakeMiddlewareCommand.php    | 19 +++--
 .../console/src/Commands/MakeModelCommand.php | 14 ++-
 vendor/webman/console/src/webman              |  8 +-
 vendor/workerman/webman-framework/src/App.php |  6 +-
 .../webman-framework/src/support/Db.php       | 15 ++++
 .../src/support/bootstrap/LaravelDb.php       |  2 +-
 .../src/support/view/Blade.php                |  6 +-
 .../webman-framework/src/support/view/Raw.php |  6 +-
 .../src/support/view/ThinkPHP.php             |  6 +-
 .../src/support/view/Twig.php                 |  6 +-
 webman                                        |  8 +-
 22 files changed, 291 insertions(+), 102 deletions(-)
 create mode 100644 vendor/webman/console/src/Commands/AppPluginUpdateCommand.php

diff --git a/app/api/controller/order/CartController.php b/app/api/controller/order/CartController.php
index 4cc4cc90..9253aaa0 100644
--- a/app/api/controller/order/CartController.php
+++ b/app/api/controller/order/CartController.php
@@ -36,15 +36,16 @@ class CartController extends BaseApiController
         if (!$branchProduct) {
             return $this->fail('商品不存在');
         }
+        $params['cart_num']=intval($params['cart_num']);
         if ($params['cart_num'] < $branchProduct['batch']) {
             return $this->fail('起批发量低于最低值' . $branchProduct['batch']);
         }
-        if ($params['cart_num']<1) {
-            $is_bulk = StoreProductUnit::where('id', $branchProduct['unit'])->value('is_bulk');
-            if ($is_bulk == 0) {
-                return $this->fail('非计量商品,不能有小数');
-            }
-        }
+        // if ($params['cart_num']<1) {
+        //     $is_bulk = StoreProductUnit::where('id', $branchProduct['unit'])->value('is_bulk');
+        //     if ($is_bulk == 0) {
+        //         return $this->fail('非计量商品,不能有小数');
+        //     }
+        // }
 
         //数量下单判断
         $count = Cart::where(['uid' => $params['uid'], 'delete_time' => null, 'is_pay' => 0])->count();
@@ -82,6 +83,7 @@ class CartController extends BaseApiController
     {
         $params = (new CartValidate())->post()->goCheck('change');
         $params['uid'] = $this->request->userId;
+        $params['cart_num']=intval($params['cart_num']);
         $res = CartLogic::edit($params, 'dec');
         if ($res) {
             return $this->success('修改成功');
diff --git a/composer.json b/composer.json
index 134d7729..d15c2d39 100644
--- a/composer.json
+++ b/composer.json
@@ -25,7 +25,7 @@
   },
   "require": {
     "php": ">=8.1",
-    "workerman/webman-framework": "v1.5.19",
+    "workerman/webman-framework": "^1.5.22",
     "monolog/monolog": "^2.2",
     "webman/think-orm": "v1.1.1",
     "vlucas/phpdotenv": "^5.4",
@@ -33,7 +33,7 @@
     "ext-json": "*",
     "phpoffice/phpspreadsheet": "^1.19",
     "aliyuncs/oss-sdk-php": "^2.6",
-    "webman/console": "^1.2.12",
+    "webman/console": "^1.3.4",
     "qiniu/php-sdk": "7.4",
     "qcloud/cos-sdk-v5": "^2.6",
     "dragonmantank/cron-expression": "^3.3",
@@ -86,4 +86,4 @@
       "support\\Plugin::uninstall"
     ]
   }
-}
\ No newline at end of file
+}
diff --git a/composer.lock b/composer.lock
index ae2caf89..ee9fc137 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "188a7d1d9e0401a1be552e084e052580",
+    "content-hash": "fb2dcd2b6d5f80016cfae906588f8bb9",
     "packages": [
         {
             "name": "aliyuncs/oss-sdk-php",
@@ -7153,23 +7153,17 @@
         },
         {
             "name": "webman/console",
-            "version": "v1.3.4",
+            "version": "v1.3.9",
             "source": {
                 "type": "git",
                 "url": "https://github.com/webman-php/console.git",
-                "reference": "ee50a1eca292eea5bf70661aa2ef722e1294814c"
+                "reference": "9ba334486b9c8dc6b88e98f423d8fedfe3d71d45"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/webman-php/console/zipball/ee50a1eca292eea5bf70661aa2ef722e1294814c",
-                "reference": "ee50a1eca292eea5bf70661aa2ef722e1294814c",
-                "shasum": "",
-                "mirrors": [
-                    {
-                        "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
-                        "preferred": true
-                    }
-                ]
+                "url": "https://api.github.com/repos/webman-php/console/zipball/9ba334486b9c8dc6b88e98f423d8fedfe3d71d45",
+                "reference": "9ba334486b9c8dc6b88e98f423d8fedfe3d71d45",
+                "shasum": ""
             },
             "require": {
                 "doctrine/inflector": "^2.0",
@@ -7208,7 +7202,7 @@
                 "source": "https://github.com/webman-php/console",
                 "wiki": "http://www.workerman.net/doc/webman"
             },
-            "time": "2024-01-23T03:25:23+00:00"
+            "time": "2024-06-12T01:30:26+00:00"
         },
         {
             "name": "webman/log",
@@ -7569,23 +7563,17 @@
         },
         {
             "name": "workerman/webman-framework",
-            "version": "v1.5.19",
+            "version": "v1.5.22",
             "source": {
                 "type": "git",
                 "url": "https://github.com/walkor/webman-framework.git",
-                "reference": "9ac7c136b0197a15a31f5092782366abff9a6e06"
+                "reference": "f52d9739a264d99d49427081c8a85303c02a770e"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/walkor/webman-framework/zipball/9ac7c136b0197a15a31f5092782366abff9a6e06",
-                "reference": "9ac7c136b0197a15a31f5092782366abff9a6e06",
-                "shasum": "",
-                "mirrors": [
-                    {
-                        "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
-                        "preferred": true
-                    }
-                ]
+                "url": "https://api.github.com/repos/walkor/webman-framework/zipball/f52d9739a264d99d49427081c8a85303c02a770e",
+                "reference": "f52d9739a264d99d49427081c8a85303c02a770e",
+                "shasum": ""
             },
             "require": {
                 "ext-json": "*",
@@ -7633,7 +7621,7 @@
                 "source": "https://github.com/walkor/webman-framework",
                 "wiki": "https://doc.workerman.net/"
             },
-            "time": "2024-06-17T01:51:40+00:00"
+            "time": "2024-08-04T01:40:07+00:00"
         },
         {
             "name": "workerman/workerman",
diff --git a/support/helpers.php b/support/helpers.php
index 8de22c00..35e94f17 100644
--- a/support/helpers.php
+++ b/support/helpers.php
@@ -73,13 +73,23 @@ function app_path(string $path = ''): string
 /**
  * Public path
  * @param string $path
+ * @param string|null $plugin
  * @return string
  */
-function public_path(string $path = ''): string
+function public_path(string $path = '', string $plugin = null): string
 {
-    static $publicPath = '';
-    if (!$publicPath) {
-        $publicPath = \config('app.public_path') ?: run_path('public');
+    static $publicPaths = [];
+    $plugin = $plugin ?? '';
+    if (isset($publicPaths[$plugin])) {
+        $publicPath = $publicPaths[$plugin];
+    } else {
+        $prefix = $plugin ? "plugin.$plugin." : '';
+        $pathPrefix = $plugin ? 'plugin' . DIRECTORY_SEPARATOR . $plugin . DIRECTORY_SEPARATOR : '';
+        $publicPath = \config("{$prefix}app.public_path", run_path("{$pathPrefix}public"));
+        if (count($publicPaths) > 32) {
+            $publicPaths = [];
+        }
+        $publicPaths[$plugin] = $publicPath;
     }
     return path_combine($publicPath, $path);
 }
@@ -244,9 +254,6 @@ function think_view(string $template, array $vars = [], string $app = null): Res
  * @param array $vars
  * @param string|null $app
  * @return Response
- * @throws LoaderError
- * @throws RuntimeError
- * @throws SyntaxError
  */
 function twig_view(string $template, array $vars = [], string $app = null): Response
 {
diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json
index 2ca13788..be31e296 100644
--- a/vendor/composer/installed.json
+++ b/vendor/composer/installed.json
@@ -7096,24 +7096,18 @@
         },
         {
             "name": "webman/console",
-            "version": "v1.3.4",
-            "version_normalized": "1.3.4.0",
+            "version": "v1.3.9",
+            "version_normalized": "1.3.9.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/webman-php/console.git",
-                "reference": "ee50a1eca292eea5bf70661aa2ef722e1294814c"
+                "reference": "9ba334486b9c8dc6b88e98f423d8fedfe3d71d45"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/webman-php/console/zipball/ee50a1eca292eea5bf70661aa2ef722e1294814c",
-                "reference": "ee50a1eca292eea5bf70661aa2ef722e1294814c",
-                "shasum": "",
-                "mirrors": [
-                    {
-                        "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
-                        "preferred": true
-                    }
-                ]
+                "url": "https://api.github.com/repos/webman-php/console/zipball/9ba334486b9c8dc6b88e98f423d8fedfe3d71d45",
+                "reference": "9ba334486b9c8dc6b88e98f423d8fedfe3d71d45",
+                "shasum": ""
             },
             "require": {
                 "doctrine/inflector": "^2.0",
@@ -7122,7 +7116,7 @@
             "require-dev": {
                 "workerman/webman": "^1.0"
             },
-            "time": "2024-01-23T03:25:23+00:00",
+            "time": "2024-06-12T01:30:26+00:00",
             "type": "library",
             "installation-source": "dist",
             "autoload": {
@@ -7509,24 +7503,18 @@
         },
         {
             "name": "workerman/webman-framework",
-            "version": "v1.5.19",
-            "version_normalized": "1.5.19.0",
+            "version": "v1.5.22",
+            "version_normalized": "1.5.22.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/walkor/webman-framework.git",
-                "reference": "9ac7c136b0197a15a31f5092782366abff9a6e06"
+                "reference": "f52d9739a264d99d49427081c8a85303c02a770e"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/walkor/webman-framework/zipball/9ac7c136b0197a15a31f5092782366abff9a6e06",
-                "reference": "9ac7c136b0197a15a31f5092782366abff9a6e06",
-                "shasum": "",
-                "mirrors": [
-                    {
-                        "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
-                        "preferred": true
-                    }
-                ]
+                "url": "https://api.github.com/repos/walkor/webman-framework/zipball/f52d9739a264d99d49427081c8a85303c02a770e",
+                "reference": "f52d9739a264d99d49427081c8a85303c02a770e",
+                "shasum": ""
             },
             "require": {
                 "ext-json": "*",
@@ -7538,7 +7526,7 @@
             "suggest": {
                 "ext-event": "For better performance. "
             },
-            "time": "2024-06-17T01:51:40+00:00",
+            "time": "2024-08-04T01:40:07+00:00",
             "type": "library",
             "installation-source": "dist",
             "autoload": {
diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php
index ccfa2790..12dfcbab 100644
--- a/vendor/composer/installed.php
+++ b/vendor/composer/installed.php
@@ -957,9 +957,9 @@
             'dev_requirement' => false,
         ),
         'webman/console' => array(
-            'pretty_version' => 'v1.3.4',
-            'version' => '1.3.4.0',
-            'reference' => 'ee50a1eca292eea5bf70661aa2ef722e1294814c',
+            'pretty_version' => 'v1.3.9',
+            'version' => '1.3.9.0',
+            'reference' => '9ba334486b9c8dc6b88e98f423d8fedfe3d71d45',
             'type' => 'library',
             'install_path' => __DIR__ . '/../webman/console',
             'aliases' => array(),
@@ -1047,9 +1047,9 @@
             'dev_requirement' => false,
         ),
         'workerman/webman-framework' => array(
-            'pretty_version' => 'v1.5.19',
-            'version' => '1.5.19.0',
-            'reference' => '9ac7c136b0197a15a31f5092782366abff9a6e06',
+            'pretty_version' => 'v1.5.22',
+            'version' => '1.5.22.0',
+            'reference' => 'f52d9739a264d99d49427081c8a85303c02a770e',
             'type' => 'library',
             'install_path' => __DIR__ . '/../workerman/webman-framework',
             'aliases' => array(),
diff --git a/vendor/webman/console/src/Commands/AppPluginCreateCommand.php b/vendor/webman/console/src/Commands/AppPluginCreateCommand.php
index ca3f186e..d1b25086 100644
--- a/vendor/webman/console/src/Commands/AppPluginCreateCommand.php
+++ b/vendor/webman/console/src/Commands/AppPluginCreateCommand.php
@@ -67,6 +67,7 @@ class AppPluginCreateCommand extends Command
         $this->createViewFile("$base_path/plugin/$name/app/view/index/index.html");
         $this->createConfigFiles("$base_path/plugin/$name/config", $name);
         $this->createApiFiles("$base_path/plugin/$name/api", $name);
+        $this->createInstallSqlFile("$base_path/plugin/$name/install.sql");
     }
 
     /**
@@ -171,9 +172,17 @@ EOF;
 namespace plugin\\$name\api;
 
 use plugin\admin\api\Menu;
+use support\Db;
+use Throwable;
 
 class Install
 {
+
+    /**
+     * 数据库连接
+     */
+    protected static \$connection = 'plugin.admin.mysql';
+    
     /**
      * 安装
      *
@@ -182,6 +191,8 @@ class Install
      */
     public static function install(\$version)
     {
+        // 安装数据库
+        static::installSql();
         // 导入菜单
         if(\$menus = static::getMenus()) {
             Menu::import(\$menus);
@@ -200,6 +211,8 @@ class Install
         foreach (static::getMenus() as \$menu) {
             Menu::delete(\$menu['key']);
         }
+        // 卸载数据库
+        static::uninstallSql();
     }
 
     /**
@@ -216,10 +229,17 @@ class Install
         if (isset(\$context['previous_menus'])) {
             static::removeUnnecessaryMenus(\$context['previous_menus']);
         }
+        // 安装数据库
+        static::installSql();
         // 导入新菜单
         if (\$menus = static::getMenus()) {
             Menu::import(\$menus);
         }
+        // 执行更新操作
+        \$update_file = __DIR__ . '/../update.php';
+        if (is_file(\$update_file)) {
+            include \$update_file;
+        }
     }
 
     /**
@@ -263,6 +283,63 @@ class Install
             Menu::delete(\$name);
         }
     }
+    
+    /**
+     * 安装SQL
+     *
+     * @return void
+     */
+    protected static function installSql()
+    {
+        static::importSql(__DIR__ . '/../install.sql');
+    }
+    
+    /**
+     * 卸载SQL
+     *
+     * @return void
+     */
+    protected static function uninstallSql() {
+        // 如果卸载数据库文件存在责直接使用
+        \$uninstallSqlFile = __DIR__ . '/../uninstall.sql';
+        if (is_file(\$uninstallSqlFile)) {
+            static::importSql(\$uninstallSqlFile);
+            return;
+        }
+        // 否则根据install.sql生成卸载数据库文件uninstall.sql
+        \$installSqlFile = __DIR__ . '/../install.sql';
+        if (!is_file(\$installSqlFile)) {
+            return;
+        }
+        \$installSql = file_get_contents(\$installSqlFile);
+        preg_match_all('/CREATE TABLE `(.+?)`/si', \$installSql, \$matches);
+        \$dropSql = '';
+        foreach (\$matches[1] as \$table) {
+            \$dropSql .= "DROP TABLE IF EXISTS `\$table`;\\n";
+        }
+        file_put_contents(\$uninstallSqlFile, \$dropSql);
+        static::importSql(\$uninstallSqlFile);
+        unlink(\$uninstallSqlFile);
+    }
+    
+    /**
+     * 导入数据库
+     *
+     * @return void
+     */
+    public static function importSql(\$mysqlDumpFile)
+    {
+        if (!\$mysqlDumpFile || !is_file(\$mysqlDumpFile)) {
+            return;
+        }
+        foreach (explode(';', file_get_contents(\$mysqlDumpFile)) as \$sql) {
+            if (\$sql = trim(\$sql)) {
+                try {
+                    Db::connection(static::\$connection)->statement(\$sql);
+                } catch (Throwable \$e) {}
+            }
+        }
+    }
 
 }
 EOF;
@@ -271,6 +348,14 @@ EOF;
 
     }
 
+    /**
+     * @return void
+     */
+    protected function createInstallSqlFile($file)
+    {
+        file_put_contents($file, '');
+    }
+
     /**
      * @param $base
      * @param $name
diff --git a/vendor/webman/console/src/Commands/AppPluginUpdateCommand.php b/vendor/webman/console/src/Commands/AppPluginUpdateCommand.php
new file mode 100644
index 00000000..a953a74c
--- /dev/null
+++ b/vendor/webman/console/src/Commands/AppPluginUpdateCommand.php
@@ -0,0 +1,42 @@
+<?php
+
+namespace Webman\Console\Commands;
+
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Webman\Console\Util;
+
+class AppPluginUpdateCommand extends Command
+{
+    protected static $defaultName = 'app-plugin:update';
+    protected static $defaultDescription = 'App Plugin Update';
+
+    /**
+     * @return void
+     */
+    protected function configure()
+    {
+        $this->addArgument('name', InputArgument::REQUIRED, 'App plugin name');
+    }
+
+    /**
+     * @param InputInterface $input
+     * @param OutputInterface $output
+     * @return int
+     */
+    protected function execute(InputInterface $input, OutputInterface $output): int
+    {
+        $name = $input->getArgument('name');
+        $output->writeln("Update App Plugin $name");
+        $class = "\\plugin\\$name\\api\\Install";
+        if (!method_exists($class, 'update')) {
+            throw new \RuntimeException("Method $class::update not exists");
+        }
+        call_user_func([$class, 'update'], config("plugin.$name.app.version"), config("plugin.$name.app.version"));
+        return self::SUCCESS;
+    }
+
+}
diff --git a/vendor/webman/console/src/Commands/MakeBootstrapCommand.php b/vendor/webman/console/src/Commands/MakeBootstrapCommand.php
index e41ced91..edd23cc8 100644
--- a/vendor/webman/console/src/Commands/MakeBootstrapCommand.php
+++ b/vendor/webman/console/src/Commands/MakeBootstrapCommand.php
@@ -6,6 +6,7 @@ use Symfony\Component\Console\Command\Command;
 use Symfony\Component\Console\Input\InputInterface;
 use Symfony\Component\Console\Output\OutputInterface;
 use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Question\ConfirmationQuestion;
 use Webman\Console\Util;
 
 
@@ -41,7 +42,7 @@ class MakeBootstrapCommand extends Command
         $upper = $bootstrap_str === 'Bootstrap';
         if (!($pos = strrpos($name, '/'))) {
             $name = ucfirst($name);
-            $file = app_path() . "/$bootstrap_str/$name.php";
+            $file = app_path() . DIRECTORY_SEPARATOR . $bootstrap_str . DIRECTORY_SEPARATOR . "$name.php";
             $namespace = $upper ? 'App\Bootstrap' : 'app\bootstrap';
         } else {
             if($real_name = Util::guessPath(app_path(), $name)) {
@@ -54,10 +55,18 @@ class MakeBootstrapCommand extends Command
             }
             $path = "$bootstrap_str/" . substr($upper ? ucfirst($name) : $name, 0, $pos);
             $name = ucfirst(substr($name, $pos + 1));
-            $file = app_path() . "/$path/$name.php";
+            $file = app_path() . DIRECTORY_SEPARATOR . $path . DIRECTORY_SEPARATOR . "$name.php";
             $namespace = str_replace('/', '\\', ($upper ? 'App/' : 'app/') . $path);
         }
 
+        if (is_file($file)) {
+            $helper = $this->getHelper('question');
+            $question = new ConfirmationQuestion("$file already exists. Do you want to override it? (yes/no)", false);
+            if (!$helper->ask($input, $output, $question)) {
+                return Command::SUCCESS;
+            }
+        }
+
         $this->createBootstrap($name, $namespace, $file);
         if ($enable) {
             $this->addConfig("$namespace\\$name", config_path() . '/bootstrap.php');
diff --git a/vendor/webman/console/src/Commands/MakeCommandCommand.php b/vendor/webman/console/src/Commands/MakeCommandCommand.php
index b60fc34c..316d3b7b 100644
--- a/vendor/webman/console/src/Commands/MakeCommandCommand.php
+++ b/vendor/webman/console/src/Commands/MakeCommandCommand.php
@@ -6,6 +6,7 @@ use Symfony\Component\Console\Command\Command;
 use Symfony\Component\Console\Input\InputInterface;
 use Symfony\Component\Console\Output\OutputInterface;
 use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Question\ConfirmationQuestion;
 use Webman\Console\Util;
 
 
@@ -42,9 +43,18 @@ class MakeCommandCommand extends Command
         foreach ($items as $item) {
             $name.=ucfirst($item);
         }
-        $file = app_path() . "/$command_str/$name.php";
+        $file = app_path() . DIRECTORY_SEPARATOR . $command_str . DIRECTORY_SEPARATOR . "$name.php";
         $upper = $command_str === 'Command';
         $namespace = $upper ? 'App\Command' : 'app\command';
+
+        if (is_file($file)) {
+            $helper = $this->getHelper('question');
+            $question = new ConfirmationQuestion("$file already exists. Do you want to override it? (yes/no)", false);
+            if (!$helper->ask($input, $output, $question)) {
+                return Command::SUCCESS;
+            }
+        }
+
         $this->createCommand($name, $namespace, $file, $command);
 
         return self::SUCCESS;
diff --git a/vendor/webman/console/src/Commands/MakeControllerCommand.php b/vendor/webman/console/src/Commands/MakeControllerCommand.php
index 3c78581d..8fc74a0c 100644
--- a/vendor/webman/console/src/Commands/MakeControllerCommand.php
+++ b/vendor/webman/console/src/Commands/MakeControllerCommand.php
@@ -6,6 +6,7 @@ use Symfony\Component\Console\Command\Command;
 use Symfony\Component\Console\Input\InputInterface;
 use Symfony\Component\Console\Output\OutputInterface;
 use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Question\ConfirmationQuestion;
 use Webman\Console\Util;
 
 
@@ -41,7 +42,7 @@ class MakeControllerCommand extends Command
         if (!($pos = strrpos($name, '/'))) {
             $name = ucfirst($name);
             $controller_str = Util::guessPath(app_path(), 'controller') ?: 'controller';
-            $file = app_path() . "/$controller_str/$name.php";
+            $file = app_path() . DIRECTORY_SEPARATOR . $controller_str . DIRECTORY_SEPARATOR . "$name.php";
             $namespace = $controller_str === 'Controller' ? 'App\Controller' : 'app\controller';
         } else {
             $name_str = substr($name, 0, $pos);
@@ -60,9 +61,18 @@ class MakeControllerCommand extends Command
             }
             $path = "$name_str/" . ($upper ? 'Controller' : 'controller');
             $name = ucfirst(substr($name, $pos + 1));
-            $file = app_path() . "/$path/$name.php";
+            $file = app_path() . DIRECTORY_SEPARATOR . $path . DIRECTORY_SEPARATOR . "$name.php";
             $namespace = str_replace('/', '\\', ($upper ? 'App/' : 'app/') . $path);
         }
+
+        if (is_file($file)) {
+            $helper = $this->getHelper('question');
+            $question = new ConfirmationQuestion("$file already exists. Do you want to override it? (yes/no)", false);
+            if (!$helper->ask($input, $output, $question)) {
+                return Command::SUCCESS;
+            }
+        }
+
         $this->createController($name, $namespace, $file);
 
         return self::SUCCESS;
diff --git a/vendor/webman/console/src/Commands/MakeMiddlewareCommand.php b/vendor/webman/console/src/Commands/MakeMiddlewareCommand.php
index 55168673..98ba5cc3 100644
--- a/vendor/webman/console/src/Commands/MakeMiddlewareCommand.php
+++ b/vendor/webman/console/src/Commands/MakeMiddlewareCommand.php
@@ -6,6 +6,7 @@ use Symfony\Component\Console\Command\Command;
 use Symfony\Component\Console\Input\InputInterface;
 use Symfony\Component\Console\Output\OutputInterface;
 use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Question\ConfirmationQuestion;
 use Webman\Console\Util;
 
 
@@ -39,7 +40,7 @@ class MakeMiddlewareCommand extends Command
         $upper = $middleware_str === 'Middleware';
         if (!($pos = strrpos($name, '/'))) {
             $name = ucfirst($name);
-            $file = app_path() . "/$middleware_str/$name.php";
+            $file = app_path() . DIRECTORY_SEPARATOR . $middleware_str . DIRECTORY_SEPARATOR . "$name.php";
             $namespace = $upper ? 'App\Middleware' : 'app\middleware';
         } else {
             if($real_name = Util::guessPath(app_path(), $name)) {
@@ -52,10 +53,18 @@ class MakeMiddlewareCommand extends Command
             }
             $path = "$middleware_str/" . substr($upper ? ucfirst($name) : $name, 0, $pos);
             $name = ucfirst(substr($name, $pos + 1));
-            $file = app_path() . "/$path/$name.php";
+            $file = app_path() . DIRECTORY_SEPARATOR . $path . DIRECTORY_SEPARATOR . "$name.php";
             $namespace = str_replace('/', '\\', ($upper ? 'App/' : 'app/') . $path);
         }
-        
+
+        if (is_file($file)) {
+            $helper = $this->getHelper('question');
+            $question = new ConfirmationQuestion("$file already exists. Do you want to override it? (yes/no)", false);
+            if (!$helper->ask($input, $output, $question)) {
+                return Command::SUCCESS;
+            }
+        }
+
         $this->createMiddleware($name, $namespace, $file);
 
         return self::SUCCESS;
@@ -84,9 +93,9 @@ use Webman\Http\Request;
 
 class $name implements MiddlewareInterface
 {
-    public function process(Request \$request, callable \$next) : Response
+    public function process(Request \$request, callable \$handler) : Response
     {
-        return \$next(\$request);
+        return \$handler(\$request);
     }
     
 }
diff --git a/vendor/webman/console/src/Commands/MakeModelCommand.php b/vendor/webman/console/src/Commands/MakeModelCommand.php
index a183dc39..deb3d1fa 100644
--- a/vendor/webman/console/src/Commands/MakeModelCommand.php
+++ b/vendor/webman/console/src/Commands/MakeModelCommand.php
@@ -9,6 +9,7 @@ use Symfony\Component\Console\Input\InputInterface;
 use Symfony\Component\Console\Output\OutputInterface;
 use Symfony\Component\Console\Input\InputOption;
 use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Question\ConfirmationQuestion;
 use Webman\Console\Util;
 
 
@@ -42,7 +43,7 @@ class MakeModelCommand extends Command
         if (!($pos = strrpos($name, '/'))) {
             $name = ucfirst($name);
             $model_str = Util::guessPath(app_path(), 'model') ?: 'model';
-            $file = app_path() . "/$model_str/$name.php";
+            $file = app_path() . DIRECTORY_SEPARATOR .  $model_str . DIRECTORY_SEPARATOR . "$name.php";
             $namespace = $model_str === 'Model' ? 'App\Model' : 'app\model';
         } else {
             $name_str = substr($name, 0, $pos);
@@ -61,7 +62,7 @@ class MakeModelCommand extends Command
             }
             $path = "$name_str/" . ($upper ? 'Model' : 'model');
             $name = ucfirst(substr($name, $pos + 1));
-            $file = app_path() . "/$path/$name.php";
+            $file = app_path() . DIRECTORY_SEPARATOR . $path . DIRECTORY_SEPARATOR . "$name.php";
             $namespace = str_replace('/', '\\', ($upper ? 'App/' : 'app/') . $path);
         }
         if (!$type) {
@@ -75,6 +76,15 @@ class MakeModelCommand extends Command
             }
             $type = !$database && $thinkorm ? 'tp' : 'laravel';
         }
+
+        if (is_file($file)) {
+            $helper = $this->getHelper('question');
+            $question = new ConfirmationQuestion("$file already exists. Do you want to override it? (yes/no)", false);
+            if (!$helper->ask($input, $output, $question)) {
+                return Command::SUCCESS;
+            }
+        }
+
         if ($type == 'tp') {
             $this->createTpModel($name, $namespace, $file, $connection);
         } else {
diff --git a/vendor/webman/console/src/webman b/vendor/webman/console/src/webman
index 69758c1c..5bca7b2c 100644
--- a/vendor/webman/console/src/webman
+++ b/vendor/webman/console/src/webman
@@ -27,9 +27,11 @@ if (is_dir($command_path = Util::guessPath(app_path(), '/command', true))) {
 
 foreach (config('plugin', []) as $firm => $projects) {
     if (isset($projects['app'])) {
-        if ($command_str = Util::guessPath(base_path() . "/plugin/$firm", 'command')) {
-            $command_path = base_path() . "/plugin/$firm/$command_str";
-            $cli->installCommands($command_path, "plugin\\$firm\\$command_str");
+        foreach (['', '/app'] as $app) {
+            if ($command_str = Util::guessPath(base_path() . "/plugin/$firm{$app}", 'command')) {
+                $command_path = base_path() . "/plugin/$firm{$app}/$command_str";
+                $cli->installCommands($command_path, "plugin\\$firm" . str_replace('/', '\\', $app) . "\\$command_str");
+            }
         }
     }
     foreach ($projects as $name => $project) {
diff --git a/vendor/workerman/webman-framework/src/App.php b/vendor/workerman/webman-framework/src/App.php
index f01db3c3..e796fb38 100644
--- a/vendor/workerman/webman-framework/src/App.php
+++ b/vendor/workerman/webman-framework/src/App.php
@@ -208,7 +208,9 @@ class App
     {
         if (
             !$path ||
-            strpos($path, '..') !== false ||
+            $path[0] !== '/' ||
+            strpos($path, '/../') !== false ||
+            substr($path, -3) === '/..' ||
             strpos($path, "\\") !== false ||
             strpos($path, "\0") !== false
         ) {
@@ -227,7 +229,7 @@ class App
      */
     protected static function getFallback(string $plugin = ''): Closure
     {
-        // when route, controller and action not found, try to use Route::fallback
+        // When route, controller and action not found, try to use Route::fallback
         return Route::getFallback($plugin) ?: function () {
             try {
                 $notFoundContent = file_get_contents(static::$publicPath . '/404.html');
diff --git a/vendor/workerman/webman-framework/src/support/Db.php b/vendor/workerman/webman-framework/src/support/Db.php
index 2bce62f0..ce0b76c9 100644
--- a/vendor/workerman/webman-framework/src/support/Db.php
+++ b/vendor/workerman/webman-framework/src/support/Db.php
@@ -16,6 +16,7 @@ namespace support;
 
 use Closure;
 use Illuminate\Database\Capsule\Manager;
+use Illuminate\Database\Connection;
 
 /**
  * Class Db
@@ -32,5 +33,19 @@ use Illuminate\Database\Capsule\Manager;
  */
 class Db extends Manager
 {
+    /**
+     * @return Manager
+     */
+    public static function getInstance()
+    {
+        return static::$instance;
+    }
 
+    /**
+     * @return Connection[]
+     */
+    public static function getConnections()
+    {
+        return static::$instance->getDatabaseManager()->getConnections();
+    }
 }
\ No newline at end of file
diff --git a/vendor/workerman/webman-framework/src/support/bootstrap/LaravelDb.php b/vendor/workerman/webman-framework/src/support/bootstrap/LaravelDb.php
index 28928b83..2ec3ed63 100644
--- a/vendor/workerman/webman-framework/src/support/bootstrap/LaravelDb.php
+++ b/vendor/workerman/webman-framework/src/support/bootstrap/LaravelDb.php
@@ -86,7 +86,7 @@ class LaravelDb implements Bootstrap
             Timer::add(55, function () use ($default, $connections, $capsule) {
                 foreach ($capsule->getDatabaseManager()->getConnections() as $connection) {
                     /* @var MySqlConnection $connection **/
-                    if ($connection->getConfig('driver') == 'mysql') {
+                    if ($connection->getConfig('driver') == 'mysql' && $connection->getRawPdo()) {
                         try {
                             $connection->select('select 1');
                         } catch (Throwable $e) {}
diff --git a/vendor/workerman/webman-framework/src/support/view/Blade.php b/vendor/workerman/webman-framework/src/support/view/Blade.php
index 99da5515..f523c197 100644
--- a/vendor/workerman/webman-framework/src/support/view/Blade.php
+++ b/vendor/workerman/webman-framework/src/support/view/Blade.php
@@ -55,7 +55,7 @@ class Blade implements View
         static $views = [];
         $request = request();
         $plugin = $plugin === null ? ($request->plugin ?? '') : $plugin;
-        $app = $app === null ? $request->app : $app;
+        $app = $app === null ? ($request->app ?? '') : $app;
         $configPrefix = $plugin ? "plugin.$plugin." : '';
         $baseViewPath = $plugin ? base_path() . "/plugin/$plugin/app" : app_path();
         $key = "$plugin-$app";
@@ -67,7 +67,9 @@ class Blade implements View
                 $extension($views[$key]);
             }
         }
-        $vars = array_merge((array) $request->_view_vars, $vars);
+        if(isset($request->_view_vars)) {
+            $vars = array_merge((array)$request->_view_vars, $vars);
+        }
         return $views[$key]->render($template, $vars);
     }
 }
diff --git a/vendor/workerman/webman-framework/src/support/view/Raw.php b/vendor/workerman/webman-framework/src/support/view/Raw.php
index 8dd3c395..2974e51d 100644
--- a/vendor/workerman/webman-framework/src/support/view/Raw.php
+++ b/vendor/workerman/webman-framework/src/support/view/Raw.php
@@ -58,11 +58,13 @@ class Raw implements View
         $plugin = $plugin === null ? ($request->plugin ?? '') : $plugin;
         $configPrefix = $plugin ? "plugin.$plugin." : '';
         $viewSuffix = config("{$configPrefix}view.options.view_suffix", 'html');
-        $app = $app === null ? $request->app : $app;
+        $app = $app === null ? ($request->app ?? '') : $app;
         $baseViewPath = $plugin ? base_path() . "/plugin/$plugin/app" : app_path();
         $__template_path__ = $app === '' ? "$baseViewPath/view/$template.$viewSuffix" : "$baseViewPath/$app/view/$template.$viewSuffix";
 
-        extract((array) $request->_view_vars);
+        if(isset($request->_view_vars)) {
+            extract((array)$request->_view_vars);
+        }
         extract($vars);
         ob_start();
         // Try to include php file.
diff --git a/vendor/workerman/webman-framework/src/support/view/ThinkPHP.php b/vendor/workerman/webman-framework/src/support/view/ThinkPHP.php
index 6923d7ef..9cc86283 100644
--- a/vendor/workerman/webman-framework/src/support/view/ThinkPHP.php
+++ b/vendor/workerman/webman-framework/src/support/view/ThinkPHP.php
@@ -55,7 +55,7 @@ class ThinkPHP implements View
     {
         $request = request();
         $plugin = $plugin === null ? ($request->plugin ?? '') : $plugin;
-        $app = $app === null ? $request->app : $app;
+        $app = $app === null ? ($request->app ?? '') : $app;
         $configPrefix = $plugin ? "plugin.$plugin." : '';
         $viewSuffix = config("{$configPrefix}view.options.view_suffix", 'html');
         $baseViewPath = $plugin ? base_path() . "/plugin/$plugin/app" : app_path();
@@ -68,7 +68,9 @@ class ThinkPHP implements View
         $options = array_merge($defaultOptions, config("{$configPrefix}view.options", []));
         $views = new Template($options);
         ob_start();
-        $vars = array_merge((array) $request->_view_vars, $vars);
+        if(isset($request->_view_vars)) {
+            $vars = array_merge((array)$request->_view_vars, $vars);
+        }
         $views->fetch($template, $vars);
         return ob_get_clean();
     }
diff --git a/vendor/workerman/webman-framework/src/support/view/Twig.php b/vendor/workerman/webman-framework/src/support/view/Twig.php
index c184655b..5ff65f45 100644
--- a/vendor/workerman/webman-framework/src/support/view/Twig.php
+++ b/vendor/workerman/webman-framework/src/support/view/Twig.php
@@ -57,7 +57,7 @@ class Twig implements View
         static $views = [];
         $request = request();
         $plugin = $plugin === null ? ($request->plugin ?? '') : $plugin;
-        $app = $app === null ? $request->app : $app;
+        $app = $app === null ? ($request->app ?? '') : $app;
         $configPrefix = $plugin ? "plugin.$plugin." : '';
         $viewSuffix = config("{$configPrefix}view.options.view_suffix", 'html');
         $key = "$plugin-$app";
@@ -70,7 +70,9 @@ class Twig implements View
                 $extension($views[$key]);
             }
         }
-        $vars = array_merge((array) $request->_view_vars, $vars);
+        if(isset($request->_view_vars)) {
+            $vars = array_merge((array)$request->_view_vars, $vars);
+        }
         return $views[$key]->render("$template.$viewSuffix", $vars);
     }
 }
diff --git a/webman b/webman
index 69758c1c..5bca7b2c 100644
--- a/webman
+++ b/webman
@@ -27,9 +27,11 @@ if (is_dir($command_path = Util::guessPath(app_path(), '/command', true))) {
 
 foreach (config('plugin', []) as $firm => $projects) {
     if (isset($projects['app'])) {
-        if ($command_str = Util::guessPath(base_path() . "/plugin/$firm", 'command')) {
-            $command_path = base_path() . "/plugin/$firm/$command_str";
-            $cli->installCommands($command_path, "plugin\\$firm\\$command_str");
+        foreach (['', '/app'] as $app) {
+            if ($command_str = Util::guessPath(base_path() . "/plugin/$firm{$app}", 'command')) {
+                $command_path = base_path() . "/plugin/$firm{$app}/$command_str";
+                $cli->installCommands($command_path, "plugin\\$firm" . str_replace('/', '\\', $app) . "\\$command_str");
+            }
         }
     }
     foreach ($projects as $name => $project) {