Browse Source

update: all denpendencies to latest version

Niels Bohr 2 years ago
parent
commit
6ccf2e9e3c

+ 0 - 0
.env_sample


+ 8 - 5
composer.json

@@ -25,19 +25,22 @@
   },
   "require": {
     "php": ">=7.2",
-    "workerman/webman-framework": "^1.3.0",
+    "workerman/webman-framework": "^1.4.3",
     "monolog/monolog": "^2.0",
     "illuminate/database": "^8.83",
     "illuminate/pagination": "^8.83",
     "illuminate/events": "^8.83",
-    "robmorgan/phinx": "^0.12.10",
+    "robmorgan/phinx": "^0.13",
     "illuminate/redis": "^8.83",
     "symfony/cache": "^5.4",
-    "webman/console": "^1.0",
-    "webman/redis-queue": "^1.1",
+    "webman/console": "^1.2",
+    "webman/redis-queue": "^1.2",
     "symfony/translation": "^5.4",
     "workerman/crontab": "^1.0",
-    "pda/pheanstalk": "^4.0"
+    "pda/pheanstalk": "^4.0",
+    "psr/container": "^1.1",
+    "twig/twig": "^3.5",
+    "vlucas/phpdotenv": "^5.5"
   },
   "suggest": {
     "ext-event": "For better performance. "

File diff suppressed because it is too large
+ 421 - 133
composer.lock


+ 0 - 5
config/plugin/vanderw/beanstalk-queue/app.php

@@ -1,5 +0,0 @@
-<?php
-
-return [
-    'enable' => true,
-];

+ 0 - 14
config/plugin/vanderw/beanstalk-queue/beanstalk.php

@@ -1,14 +0,0 @@
-<?php
-
-return [
-    'default' => [
-        'ip' => '127.0.0.1',
-        'port' => 11300,
-        'timeout' => 10, // s
-        'options' => [
-            'auth' => '123456', // 密码,可选参数
-            'delay'  => 2,      // 延遲秒數
-            'retry_after' => 5, // 秒後重试
-        ]
-    ],
-];

+ 0 - 7
config/plugin/vanderw/beanstalk-queue/command.php

@@ -1,7 +0,0 @@
-<?php
-
-use Vanderw\BeanstalkQueue\Command\MakeConsumerCommand;
-
-return [
-    MakeConsumerCommand::class
-];

+ 0 - 12
config/plugin/vanderw/beanstalk-queue/process.php

@@ -1,12 +0,0 @@
-<?php
-
-return [
-    'consumer'  => [
-        'handler'     => Vanderw\BeanstalkQueue\Process\Consumer::class,
-        'count'       => 1, // 可以设置多进程同时消费
-        'constructor' => [
-            // 消费者类目录
-            'consumer_dir' => app_path() . '/queue/beanstalk'
-        ]
-    ]
-];

+ 0 - 0
phinx.php → phinx.sample.php


+ 1 - 105
start.php

@@ -1,108 +1,4 @@
 #!/usr/bin/env php
 <?php
 require_once __DIR__ . '/vendor/autoload.php';
-
-use Workerman\Worker;
-use Workerman\Protocols\Http;
-use Workerman\Connection\TcpConnection;
-use Webman\App;
-use Webman\Config;
-use Webman\Route;
-use Webman\Middleware;
-use Dotenv\Dotenv;
-use support\Request;
-use support\Log;
-use support\Container;
-
-ini_set('display_errors', 'on');
-error_reporting(E_ALL);
-
-if (class_exists('Dotenv\Dotenv') && file_exists(base_path() . '/.env')) {
-    if (method_exists('Dotenv\Dotenv', 'createUnsafeImmutable')) {
-        Dotenv::createUnsafeImmutable(base_path())->load();
-    } else {
-        Dotenv::createMutable(base_path())->load();
-    }
-}
-
-Config::load(config_path(), ['route', 'container']);
-
-if ($timezone = config('app.default_timezone')) {
-    date_default_timezone_set($timezone);
-}
-
-$runtime_logs_path = runtime_path() . DIRECTORY_SEPARATOR . 'logs';
-if ( !file_exists($runtime_logs_path) || !is_dir($runtime_logs_path) ) {
-    if (!mkdir($runtime_logs_path,0777,true)) {
-        throw new \RuntimeException("Failed to create runtime logs directory. Please check the permission.");
-    }
-}
-
-$runtime_views_path = runtime_path() . DIRECTORY_SEPARATOR . 'views';
-if ( !file_exists($runtime_views_path) || !is_dir($runtime_views_path) ) {
-    if (!mkdir($runtime_views_path,0777,true)) {
-        throw new \RuntimeException("Failed to create runtime views directory. Please check the permission.");
-    }
-}
-
-Worker::$onMasterReload = function () {
-    if (function_exists('opcache_get_status')) {
-        if ($status = opcache_get_status()) {
-            if (isset($status['scripts']) && $scripts = $status['scripts']) {
-                foreach (array_keys($scripts) as $file) {
-                    opcache_invalidate($file, true);
-                }
-            }
-        }
-    }
-};
-
-$config = config('server');
-Worker::$pidFile = $config['pid_file'];
-Worker::$stdoutFile = $config['stdout_file'];
-Worker::$logFile = $config['log_file'];
-Worker::$eventLoopClass = $config['event_loop'] ?? '';
-TcpConnection::$defaultMaxPackageSize = $config['max_package_size'] ?? 10 * 1024 * 1024;
-if (property_exists(Worker::class, 'statusFile')) {
-    Worker::$statusFile = $config['status_file'] ?? '';
-}
-
-if ($config['listen']) {
-    $worker = new Worker($config['listen'], $config['context']);
-    $property_map = [
-        'name',
-        'count',
-        'user',
-        'group',
-        'reusePort',
-        'transport',
-    ];
-    foreach ($property_map as $property) {
-        if (isset($config[$property])) {
-            $worker->$property = $config[$property];
-        }
-    }
-
-    $worker->onWorkerStart = function ($worker) {
-        require_once base_path() . '/support/bootstrap.php';
-        $app = new App($worker, Container::instance(), Log::channel('default'), app_path(), public_path());
-        Http::requestClass(config('app.request_class', config('server.request_class', Request::class)));
-        $worker->onMessage = [$app, 'onMessage'];
-    };
-}
-
-// Windows does not support custom processes.
-if (\DIRECTORY_SEPARATOR === '/') {
-    foreach (config('process', []) as $process_name => $config) {
-        worker_start($process_name, $config);
-    }
-    foreach (config('plugin', []) as $firm => $projects) {
-        foreach ($projects as $name => $project) {
-            foreach ($project['process'] ?? [] as $process_name => $config) {
-                worker_start("plugin.$firm.$name.$process_name", $config);
-            }
-        }
-    }
-}
-
-Worker::runAll();
+support\App::run();

+ 63 - 21
support/bootstrap.php

@@ -13,18 +13,16 @@
  */
 
 use Dotenv\Dotenv;
-use support\Container;
+use support\Log;
+use Webman\Bootstrap;
 use Webman\Config;
 use Webman\Route;
 use Webman\Middleware;
+use Webman\Util;
 
 $worker = $worker ?? null;
 
-if ($timezone = config('app.default_timezone')) {
-    date_default_timezone_set($timezone);
-}
-
-set_error_handler(function ($level, $message, $file = '', $line = 0, $context = []) {
+set_error_handler(function ($level, $message, $file = '', $line = 0) {
     if (error_reporting() & $level) {
         throw new ErrorException($message, 0, $level, $file, $line);
     }
@@ -46,45 +44,89 @@ if (class_exists('Dotenv\Dotenv') && file_exists(base_path() . '/.env')) {
     }
 }
 
-Config::reload(config_path(), ['route', 'container']);
+Config::clear();
+support\App::loadAllConfig(['route']);
+if ($timezone = config('app.default_timezone')) {
+    date_default_timezone_set($timezone);
+}
 
+foreach (config('autoload.files', []) as $file) {
+    include_once $file;
+}
 foreach (config('plugin', []) as $firm => $projects) {
     foreach ($projects as $name => $project) {
+        if (!is_array($project)) {
+            continue;
+        }
         foreach ($project['autoload']['files'] ?? [] as $file) {
             include_once $file;
         }
     }
+    foreach ($projects['autoload']['files'] ?? [] as $file) {
+        include_once $file;
+    }
 }
 
-foreach (config('autoload.files', []) as $file) {
-    include_once $file;
-}
-
-$container = Container::instance();
-Route::container($container);
-Middleware::container($container);
-
-Middleware::load(config('middleware', []));
+Middleware::load(config('middleware', []), '');
 foreach (config('plugin', []) as $firm => $projects) {
     foreach ($projects as $name => $project) {
-        Middleware::load($project['middleware'] ?? []);
+        if (!is_array($project) || $name === 'static') {
+            continue;
+        }
+        Middleware::load($project['middleware'] ?? [], '');
+    }
+    Middleware::load($projects['middleware'] ?? [], $firm);
+    if ($static_middlewares = config("plugin.$firm.static.middleware")) {
+        Middleware::load(['__static__' => $static_middlewares], $firm);
     }
 }
-Middleware::load(['__static__' => config('static.middleware', [])]);
+Middleware::load(['__static__' => config('static.middleware', [])], '');
 
 foreach (config('bootstrap', []) as $class_name) {
-    /** @var \Webman\Bootstrap $class_name */
+    if (!class_exists($class_name)) {
+        $log = "Warning: Class $class_name setting in config/bootstrap.php not found\r\n";
+        echo $log;
+        Log::error($log);
+        continue;
+    }
+    /** @var Bootstrap $class_name */
     $class_name::start($worker);
 }
 
 foreach (config('plugin', []) as $firm => $projects) {
     foreach ($projects as $name => $project) {
+        if (!is_array($project)) {
+            continue;
+        }
         foreach ($project['bootstrap'] ?? [] as $class_name) {
-            /** @var \Webman\Bootstrap $class_name */
+            if (!class_exists($class_name)) {
+                $log = "Warning: Class $class_name setting in config/plugin/$firm/$name/bootstrap.php not found\r\n";
+                echo $log;
+                Log::error($log);
+                continue;
+            }
+            /** @var Bootstrap $class_name */
             $class_name::start($worker);
         }
     }
+    foreach ($projects['bootstrap'] ?? [] as $class_name) {
+        if (!class_exists($class_name)) {
+            $log = "Warning: Class $class_name setting in plugin/$firm/config/bootstrap.php not found\r\n";
+            echo $log;
+            Log::error($log);
+            continue;
+        }
+        /** @var Bootstrap $class_name */
+        $class_name::start($worker);
+    }
 }
 
-Route::load(config_path());
+$directory = base_path() . '/plugin';
+$paths = [config_path()];
+foreach (Util::scanDir($directory) as $path) {
+    if (is_dir($path = "$path/config")) {
+        $paths[] = $path;
+    }
+}
+Route::load($paths);
 

+ 186 - 119
support/helpers.php

@@ -1,4 +1,5 @@
 <?php
+
 /**
  * This file is part of webman.
  *
@@ -12,10 +13,10 @@
  * @license   http://www.opensource.org/licenses/mit-license.php MIT License
  */
 
+use support\Container;
 use support\Request;
 use support\Response;
 use support\Translation;
-use support\Container;
 use support\view\Raw;
 use support\view\Blade;
 use support\view\ThinkPHP;
@@ -25,96 +26,127 @@ use Webman\App;
 use Webman\Config;
 use Webman\Route;
 
-// Phar support.
-if (is_phar()) {
-    define('BASE_PATH', dirname(__DIR__));
-} else {
-    define('BASE_PATH', realpath(__DIR__ . '/../'));
+// Webman version
+const WEBMAN_VERSION = '1.4';
+
+// Project base path
+define('BASE_PATH', dirname(__DIR__));
+
+/**
+ * return the program execute directory
+ * @param string $path
+ * @return string
+ */
+function run_path(string $path = ''): string
+{
+    static $run_path = '';
+    if (!$run_path) {
+        $run_path = \is_phar() ? \dirname(\Phar::running(false)) : BASE_PATH;
+    }
+    return \path_combine($run_path, $path);
 }
-define('WEBMAN_VERSION', '1.3.0');
 
 /**
- * @param $return_phar
- * @return false|string
+ * if the param $path equal false,will return this program current execute directory
+ * @param string|false $path
+ * @return string
  */
-function base_path($return_phar = true)
+function base_path($path = ''): string
 {
-    static $real_path = '';
-    if (!$real_path) {
-        $real_path = is_phar() ? dirname(Phar::running(false)) : BASE_PATH;
+    if (false === $path) {
+        return \run_path();
     }
-    return $return_phar ? BASE_PATH : $real_path;
+    return \path_combine(BASE_PATH, $path);
 }
 
 /**
+ * App path
+ * @param string $path
  * @return string
  */
-function app_path()
+function app_path(string $path = ''): string
 {
-    return BASE_PATH . DIRECTORY_SEPARATOR . 'app';
+    return \path_combine(BASE_PATH . DIRECTORY_SEPARATOR . 'app', $path);
 }
 
 /**
+ * Public path
+ * @param string $path
  * @return string
  */
-function public_path()
+function public_path(string $path = ''): string
 {
-    static $path = '';
-    if (!$path) {
-        $path = get_realpath(config('app.public_path', BASE_PATH . DIRECTORY_SEPARATOR . 'public'));
+    static $public_path = '';
+    if (!$public_path) {
+        $public_path = \config('app.public_path') ? : \run_path('public');
     }
-    return $path;
+    return \path_combine($public_path, $path);
 }
 
 /**
+ * Config path
+ * @param string $path
  * @return string
  */
-function config_path()
+function config_path(string $path = ''): string
 {
-    return BASE_PATH . DIRECTORY_SEPARATOR . 'config';
+    return \path_combine(BASE_PATH . DIRECTORY_SEPARATOR . 'config', $path);
 }
 
 /**
- * Phar support.
- * Compatible with the 'realpath' function in the phar file.
- *
+ * Runtime path
+ * @param string $path
  * @return string
  */
-function runtime_path()
+function runtime_path(string $path = ''): string
 {
-    static $path = '';
-    if (!$path) {
-        $path = get_realpath(config('app.runtime_path', BASE_PATH . DIRECTORY_SEPARATOR . 'runtime'));
+    static $runtime_path = '';
+    if (!$runtime_path) {
+        $runtime_path = \config('app.runtime_path') ? : \run_path('runtime');
     }
-    return $path;
+    return \path_combine($runtime_path, $path);
 }
 
 /**
+ * Generate paths based on given information
+ * @param string $front
+ * @param string $back
+ * @return string
+ */
+function path_combine(string $front, string $back): string
+{
+    return $front . ($back ? (DIRECTORY_SEPARATOR . ltrim($back, DIRECTORY_SEPARATOR)) : $back);
+}
+
+/**
+ * Response
  * @param int $status
  * @param array $headers
  * @param string $body
  * @return Response
  */
-function response($body = '', $status = 200, $headers = array())
+function response(string $body = '', int $status = 200, array $headers = []): Response
 {
     return new Response($status, $headers, $body);
 }
 
 /**
+ * Json response
  * @param $data
  * @param int $options
  * @return Response
  */
-function json($data, $options = JSON_UNESCAPED_UNICODE)
+function json($data, int $options = JSON_UNESCAPED_UNICODE): Response
 {
-    return new Response(200, ['Content-Type' => 'application/json'], json_encode($data, $options));
+    return new Response(200, ['Content-Type' => 'application/json'], \json_encode($data, $options));
 }
 
 /**
+ * Xml response
  * @param $xml
  * @return Response
  */
-function xml($xml)
+function xml($xml): Response
 {
     if ($xml instanceof SimpleXMLElement) {
         $xml = $xml->asXML();
@@ -123,25 +155,27 @@ function xml($xml)
 }
 
 /**
+ * Jsonp response
  * @param $data
  * @param string $callback_name
  * @return Response
  */
-function jsonp($data, $callback_name = 'callback')
+function jsonp($data, string $callback_name = 'callback'): Response
 {
-    if (!is_scalar($data) && null !== $data) {
-        $data = json_encode($data);
+    if (!\is_scalar($data) && null !== $data) {
+        $data = \json_encode($data);
     }
     return new Response(200, [], "$callback_name($data)");
 }
 
 /**
- * @param $location
+ * Redirect response
+ * @param string $location
  * @param int $status
  * @param array $headers
  * @return Response
  */
-function redirect($location, $status = 302, $headers = [])
+function redirect(string $location, int $status = 302, array $headers = []): Response
 {
     $response = new Response($status, ['Location' => $location]);
     if (!empty($headers)) {
@@ -151,66 +185,72 @@ function redirect($location, $status = 302, $headers = [])
 }
 
 /**
- * @param $template
+ * View response
+ * @param string $template
  * @param array $vars
- * @param null $app
+ * @param string|null $app
  * @return Response
  */
-function view($template, $vars = [], $app = null)
+function view(string $template, array $vars = [], string $app = null): Response
 {
-    static $handler;
-    if (null === $handler) {
-        $handler = config('view.handler');
-    }
+    $request = \request();
+    $plugin =  $request->plugin ?? '';
+    $handler = \config($plugin ? "plugin.$plugin.view.handler" : 'view.handler');
     return new Response(200, [], $handler::render($template, $vars, $app));
 }
 
 /**
- * @param $template
+ * Raw view response
+ * @param string $template
  * @param array $vars
- * @param null $app
+ * @param string|null $app
  * @return Response
+ * @throws Throwable
  */
-function raw_view($template, $vars = [], $app = null)
+function raw_view(string $template, array $vars = [], string $app = null): Response
 {
     return new Response(200, [], Raw::render($template, $vars, $app));
 }
 
 /**
- * @param $template
+ * Blade view response
+ * @param string $template
  * @param array $vars
- * @param null $app
+ * @param string|null $app
  * @return Response
  */
-function blade_view($template, $vars = [], $app = null)
+function blade_view(string $template, array $vars = [], string $app = null): Response
 {
     return new Response(200, [], Blade::render($template, $vars, $app));
 }
 
 /**
- * @param $template
+ * Think view response
+ * @param string $template
  * @param array $vars
- * @param null $app
+ * @param string|null $app
  * @return Response
  */
-function think_view($template, $vars = [], $app = null)
+function think_view(string $template, array $vars = [], string $app = null): Response
 {
     return new Response(200, [], ThinkPHP::render($template, $vars, $app));
 }
 
 /**
- * @param $template
+ * Twig view response
+ * @param string $template
  * @param array $vars
- * @param null $app
+ * @param string|null $app
  * @return Response
  */
-function twig_view($template, $vars = [], $app = null)
+function twig_view(string $template, array $vars = [], string $app = null): Response
 {
     return new Response(200, [], Twig::render($template, $vars, $app));
 }
 
 /**
- * @return Request
+ * Get request
+ * @return \Webman\Http\Request|Request|null
  */
 function request()
 {
@@ -218,37 +258,49 @@ function request()
 }
 
 /**
- * @param $key
- * @param null $default
- * @return mixed
+ * Get config
+ * @param string|null $key
+ * @param $default
+ * @return array|mixed|null
  */
-function config($key = null, $default = null)
+function config(string $key = null, $default = null)
 {
     return Config::get($key, $default);
 }
 
 /**
- * @param $name
- * @param array $parameters
+ * Create url
+ * @param string $name
+ * @param ...$parameters
  * @return string
  */
-function route($name, $parameters = [])
+function route(string $name, ...$parameters): string
 {
     $route = Route::getByName($name);
     if (!$route) {
         return '';
     }
+
+    if (!$parameters) {
+        return $route->url();
+    }
+
+    if (\is_array(\current($parameters))) {
+        $parameters = \current($parameters);
+    }
+
     return $route->url($parameters);
 }
 
 /**
- * @param null $key
- * @param null $default
+ * Session
+ * @param mixed $key
+ * @param mixed $default
  * @return mixed
  */
 function session($key = null, $default = null)
 {
-    $session = request()->session();
+    $session = \request()->session();
     if (null === $key) {
         return $session;
     }
@@ -256,27 +308,40 @@ function session($key = null, $default = null)
         $session->put($key);
         return null;
     }
+    if (\strpos($key, '.')) {
+        $key_array = \explode('.', $key);
+        $value = $session->all();
+        foreach ($key_array as $index) {
+            if (!isset($value[$index])) {
+                return $default;
+            }
+            $value = $value[$index];
+        }
+        return $value;
+    }
     return $session->get($key, $default);
 }
 
 /**
- * @param null|string $id
+ * Translation
+ * @param string $id
  * @param array $parameters
  * @param string|null $domain
  * @param string|null $locale
  * @return string
  */
-function trans(string $id, array $parameters = [], string $domain = null, string $locale = null)
+function trans(string $id, array $parameters = [], string $domain = null, string $locale = null): string
 {
     $res = Translation::trans($id, $parameters, $domain, $locale);
     return $res === '' ? $id : $res;
 }
 
 /**
- * @param null|string $locale
- * @return string
+ * Locale
+ * @param string|null $locale
+ * @return void
  */
-function locale(string $locale = null)
+function locale(string $locale = null): string
 {
     if (!$locale) {
         return Translation::getLocale();
@@ -286,56 +351,56 @@ function locale(string $locale = null)
 
 /**
  * 404 not found
- *
  * @return Response
  */
-function not_found()
+function not_found(): Response
 {
-    return new Response(404, [], file_get_contents(public_path() . '/404.html'));
+    return new Response(404, [], \file_get_contents(public_path() . '/404.html'));
 }
 
 /**
- * Copy dir.
- * @param $source
- * @param $dest
+ * Copy dir
+ * @param string $source
+ * @param string $dest
  * @param bool $overwrite
  * @return void
  */
-function copy_dir($source, $dest, $overwrite = false)
+function copy_dir(string $source, string $dest, bool $overwrite = false)
 {
-    if (is_dir($source)) {
+    if (\is_dir($source)) {
         if (!is_dir($dest)) {
-            mkdir($dest);
+            \mkdir($dest);
         }
-        $files = scandir($source);
+        $files = \scandir($source);
         foreach ($files as $file) {
             if ($file !== "." && $file !== "..") {
-                copy_dir("$source/$file", "$dest/$file");
+                \copy_dir("$source/$file", "$dest/$file");
             }
         }
-    } else if (file_exists($source) && ($overwrite || !file_exists($dest))) {
-        copy($source, $dest);
+    } else if (\file_exists($source) && ($overwrite || !\file_exists($dest))) {
+        \copy($source, $dest);
     }
 }
 
 /**
- * Remove dir.
- * @param $dir
+ * Remove dir
+ * @param string $dir
  * @return bool
  */
-function remove_dir($dir)
+function remove_dir(string $dir): bool
 {
-    if (is_link($dir) || is_file($dir)) {
-        return unlink($dir);
+    if (\is_link($dir) || \is_file($dir)) {
+        return \unlink($dir);
     }
-    $files = array_diff(scandir($dir), array('.', '..'));
+    $files = \array_diff(\scandir($dir), array('.', '..'));
     foreach ($files as $file) {
-        (is_dir("$dir/$file") && !is_link($dir)) ? remove_dir("$dir/$file") : unlink("$dir/$file");
+        (\is_dir("$dir/$file") && !\is_link($dir)) ? \remove_dir("$dir/$file") : \unlink("$dir/$file");
     }
-    return rmdir($dir);
+    return \rmdir($dir);
 }
 
 /**
+ * Bind worker
  * @param $worker
  * @param $class
  */
@@ -352,16 +417,17 @@ function worker_bind($worker, $class)
         'onWebSocketConnect'
     ];
     foreach ($callback_map as $name) {
-        if (method_exists($class, $name)) {
+        if (\method_exists($class, $name)) {
             $worker->$name = [$class, $name];
         }
     }
-    if (method_exists($class, 'onWorkerStart')) {
-        call_user_func([$class, 'onWorkerStart'], $worker);
+    if (\method_exists($class, 'onWorkerStart')) {
+        \call_user_func([$class, 'onWorkerStart'], $worker);
     }
 }
 
 /**
+ * Start worker
  * @param $process_name
  * @param $config
  * @return void
@@ -386,10 +452,10 @@ function worker_start($process_name, $config)
     }
 
     $worker->onWorkerStart = function ($worker) use ($config) {
-        require_once base_path() . '/support/bootstrap.php';
+        require_once \base_path() . '/support/bootstrap.php';
 
         foreach ($config['services'] ?? [] as $server) {
-            if (!class_exists($server['handler'])) {
+            if (!\class_exists($server['handler'])) {
                 echo "process error: class {$server['handler']} not exists\r\n";
                 continue;
             }
@@ -398,61 +464,62 @@ function worker_start($process_name, $config)
                 echo "listen: {$server['listen']}\n";
             }
             $instance = Container::make($server['handler'], $server['constructor'] ?? []);
-            worker_bind($listen, $instance);
+            \worker_bind($listen, $instance);
             $listen->listen();
         }
 
         if (isset($config['handler'])) {
-            if (!class_exists($config['handler'])) {
+            if (!\class_exists($config['handler'])) {
                 echo "process error: class {$config['handler']} not exists\r\n";
                 return;
             }
 
             $instance = Container::make($config['handler'], $config['constructor'] ?? []);
-            worker_bind($worker, $instance);
+            \worker_bind($worker, $instance);
         }
-
     };
 }
 
 /**
- * Phar support.
- * Compatible with the 'realpath' function in the phar file.
- *
+ * Get realpath
  * @param string $file_path
  * @return string
  */
 function get_realpath(string $file_path): string
 {
-    if (strpos($file_path, 'phar://') === 0) {
+    if (\strpos($file_path, 'phar://') === 0) {
         return $file_path;
     } else {
-        return realpath($file_path);
+        return \realpath($file_path);
     }
 }
 
 /**
+ * Is phar
  * @return bool
  */
-function is_phar()
+function is_phar(): bool
 {
-    return class_exists(\Phar::class, false) && Phar::running();
+    return \class_exists(\Phar::class, false) && Phar::running();
 }
 
 /**
+ * Get cpu count
  * @return int
  */
-function cpu_count()
+function cpu_count(): int
 {
     // Windows does not support the number of processes setting.
     if (\DIRECTORY_SEPARATOR === '\\') {
         return 1;
     }
-    if (strtolower(PHP_OS) === 'darwin') {
-        $count = shell_exec('sysctl -n machdep.cpu.core_count');
-    } else {
-        $count = shell_exec('nproc');
+    $count = 4;
+    if (\is_callable('shell_exec')) {
+        if (\strtolower(PHP_OS) === 'darwin') {
+            $count = (int)\shell_exec('sysctl -n machdep.cpu.core_count');
+        } else {
+            $count = (int)\shell_exec('nproc');
+        }
     }
-    $count = (int)$count > 0 ? (int)$count : 4;
-    return $count;
+    return $count > 0 ? $count : 4;
 }

+ 52 - 32
windows.php

@@ -5,13 +5,27 @@
 require_once __DIR__ . '/vendor/autoload.php';
 
 use process\Monitor;
+use support\App;
+use Dotenv\Dotenv;
 use Workerman\Worker;
-use Webman\Config;
 
 ini_set('display_errors', 'on');
 error_reporting(E_ALL);
 
-Config::load(config_path(), ['route', 'container']);
+if (class_exists('Dotenv\Dotenv') && file_exists(base_path() . '/.env')) {
+    if (method_exists('Dotenv\Dotenv', 'createUnsafeImmutable')) {
+        Dotenv::createUnsafeImmutable(base_path())->load();
+    } else {
+        Dotenv::createMutable(base_path())->load();
+    }
+}
+
+App::loadAllConfig(['route']);
+
+$error_reporting = config('app.error_reporting');
+if (isset($error_reporting)) {
+    error_reporting($error_reporting);
+}
 
 $runtime_process_path = runtime_path() . DIRECTORY_SEPARATOR . '/windows';
 if (!is_dir($runtime_process_path)) {
@@ -21,55 +35,61 @@ $process_files = [
     __DIR__ . DIRECTORY_SEPARATOR . 'start.php'
 ];
 foreach (config('process', []) as $process_name => $config) {
-    $file_content = <<<EOF
-<?php
-require_once __DIR__ . '/../../vendor/autoload.php';
-
-use Workerman\Worker;
-use Webman\Config;
-
-ini_set('display_errors', 'on');
-error_reporting(E_ALL);
-
-Config::load(config_path(), ['route', 'container']);
-
-worker_start('$process_name', config('process')['$process_name']);
-Worker::runAll();
-
-EOF;
-
-    $process_file = $runtime_process_path . DIRECTORY_SEPARATOR . "start_$process_name.php";
-    $process_files[] = $process_file;
-    file_put_contents($process_file, $file_content);
+    $process_files[] = write_process_file($runtime_process_path, $process_name, '');
 }
 
 foreach (config('plugin', []) as $firm => $projects) {
     foreach ($projects as $name => $project) {
+        if (!is_array($project)) {
+            continue;
+        }
         foreach ($project['process'] ?? [] as $process_name => $config) {
-            $file_content = <<<EOF
+            $process_files[] = write_process_file($runtime_process_path, $process_name, "$firm.$name");
+        }
+    }
+    foreach ($projects['process'] ?? [] as $process_name => $config) {
+        $process_files[] = write_process_file($runtime_process_path, $process_name, $firm);
+    }
+}
+
+function write_process_file($runtime_process_path, $process_name, $firm)
+{
+    $process_param = $firm ? "plugin.$firm.$process_name" : $process_name;
+    $config_param = $firm ? "config('plugin.$firm.process')['$process_name']" : "config('process')['$process_name']";
+    $file_content = <<<EOF
 <?php
 require_once __DIR__ . '/../../vendor/autoload.php';
 
 use Workerman\Worker;
 use Webman\Config;
+use support\App;
 
 ini_set('display_errors', 'on');
 error_reporting(E_ALL);
 
-Config::load(config_path(), ['route', 'container']);
+if (is_callable('opcache_reset')) {
+    opcache_reset();
+}
+
+App::loadAllConfig(['route']);
+
+worker_start('$process_param', $config_param);
+
+if (DIRECTORY_SEPARATOR != "/") {
+    Worker::\$logFile = config('server')['log_file'] ?? Worker::\$logFile;
+}
 
-worker_start("plugin.$firm.$name.$process_name", config("plugin.$firm.$name.process")['$process_name']);
 Worker::runAll();
 
 EOF;
-            $process_file = $runtime_process_path . DIRECTORY_SEPARATOR . "start_$process_name.php";
-            $process_files[] = $process_file;
-            file_put_contents($process_file, $file_content);
-        }
-    }
+    $process_file = $runtime_process_path . DIRECTORY_SEPARATOR . "start_$process_param.php";
+    file_put_contents($process_file, $file_content);
+    return $process_file;
 }
 
-$monitor = new Monitor(...array_values(config('process.monitor.constructor')));
+if ($monitor_config = config('process.monitor.constructor')) {
+    $monitor = new Monitor(...array_values($monitor_config));
+}
 
 function popen_processes($process_files)
 {
@@ -86,7 +106,7 @@ $resource = popen_processes($process_files);
 echo "\r\n";
 while (1) {
     sleep(1);
-    if ($monitor->checkAllFilesChange()) {
+    if (!empty($monitor) && $monitor->checkAllFilesChange()) {
         $status = proc_get_status($resource);
         $pid = $status['pid'];
         shell_exec("taskkill /F /T /PID $pid");

Some files were not shown because too many files changed in this diff