Commit 0803a1fe authored by wolfcode's avatar wolfcode

update Core && fix bug

parent 3eb27bc2
...@@ -50,19 +50,20 @@ class InstallCheck implements MiddlewareInterface ...@@ -50,19 +50,20 @@ class InstallCheck implements MiddlewareInterface
try { try {
$conn = mysqli_connect($dbHost, $dbUser, $dbPwd, null, $dbPort); $conn = mysqli_connect($dbHost, $dbUser, $dbPwd, null, $dbPort);
mysqli_query($conn, "SET NAMES {$dbCharset}"); mysqli_query($conn, "SET NAMES {$dbCharset}");
$initDb = mysqli_select_db($conn, $dbName); try {
if (!$initDb) { mysqli_select_db($conn, $dbName);
} catch (\mysqli_sql_exception $exception) {
if (!mysqli_query($conn, "CREATE DATABASE IF NOT EXISTS `{$dbName}` DEFAULT CHARACTER SET {$dbCharset};")) { if (!mysqli_query($conn, "CREATE DATABASE IF NOT EXISTS `{$dbName}` DEFAULT CHARACTER SET {$dbCharset};")) {
$errorMsg = "数据库{$dbName} 不存在,也没权限创建新的数据库!"; $errorMsg = "数据库{$dbName} 不存在,也没权限创建新的数据库!";
mysqli_close($conn); mysqli_close($conn);
return response($errorMsg, 400); return response($errorMsg, 400);
} }
mysqli_select_db($conn, $dbName);
} }
// 先建表 // 先建表
$db_data = file_get_contents($db_base_data); $db_data = file_get_contents($db_base_data);
$sqlFormat = sql_split($db_data); $sqlFormat = sql_split($db_data);
$counts = count($sqlFormat); $counts = count($sqlFormat);
mysqli_select_db($conn, $dbName);
for ($index = 0; $index < $counts; $index++) { for ($index = 0; $index < $counts; $index++) {
$sql = trim($sqlFormat[$index]); $sql = trim($sqlFormat[$index]);
if (strstr($sql, 'CREATE TABLE')) { if (strstr($sql, 'CREATE TABLE')) {
...@@ -79,7 +80,7 @@ class InstallCheck implements MiddlewareInterface ...@@ -79,7 +80,7 @@ class InstallCheck implements MiddlewareInterface
mysqli_close($conn); mysqli_close($conn);
@touch($lock_file); @touch($lock_file);
return $handler($request); return $handler($request);
} catch (\Exception $e) { } catch (\Throwable $e) {
$errorMsg = "连接 MySQL 失败: " . mysqli_connect_error() . $e->getMessage(); $errorMsg = "连接 MySQL 失败: " . mysqli_connect_error() . $e->getMessage();
return response($errorMsg, 400); return response($errorMsg, 400);
} }
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
}, },
"require": { "require": {
"php": ">=7.2", "php": ">=7.2",
"workerman/webman-framework": "^1.3.0", "workerman/webman-framework": "1.4.3",
"monolog/monolog": "^2.0", "monolog/monolog": "^2.0",
"webman/auto-route": "^1.0", "webman/auto-route": "^1.0",
"webman/think-orm": "1.0.2", "webman/think-orm": "1.0.2",
...@@ -40,7 +40,8 @@ ...@@ -40,7 +40,8 @@
"webman/think-cache": "^1.0", "webman/think-cache": "^1.0",
"aliyuncs/oss-sdk-php": "^2.4", "aliyuncs/oss-sdk-php": "^2.4",
"qcloud/cos-sdk-v5": "^2.5", "qcloud/cos-sdk-v5": "^2.5",
"jasongrimes/paginator": "^1.0" "jasongrimes/paginator": "^1.0",
"webman/console": "1.0.27"
}, },
"suggest": { "suggest": {
"ext-event": "For better performance. " "ext-event": "For better performance. "
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "02d0c65ff3d87ccf79b24943c0ba01d7", "content-hash": "1e7532d2b14481835ed4cafcfb0c520b",
"packages": [ "packages": [
{ {
"name": "aliyuncs/oss-sdk-php", "name": "aliyuncs/oss-sdk-php",
...@@ -3634,6 +3634,58 @@ ...@@ -3634,6 +3634,58 @@
}, },
"time": "2022-04-01T07:37:43+00:00" "time": "2022-04-01T07:37:43+00:00"
}, },
{
"name": "webman/console",
"version": "v1.0.27",
"source": {
"type": "git",
"url": "https://github.com/webman-php/console.git",
"reference": "e450967eaabc43eb0c93cfcd6d8f420c16e22b67"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/webman-php/console/zipball/e450967eaabc43eb0c93cfcd6d8f420c16e22b67",
"reference": "e450967eaabc43eb0c93cfcd6d8f420c16e22b67",
"shasum": ""
},
"require": {
"symfony/console": ">=5.0"
},
"require-dev": {
"workerman/webman": "^1.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Webman\\Console\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "walkor",
"email": "walkor@workerman.net",
"homepage": "http://www.workerman.net",
"role": "Developer"
}
],
"description": "Webman console",
"homepage": "http://www.workerman.net",
"keywords": [
"webman console"
],
"support": {
"email": "walkor@workerman.net",
"forum": "http://www.workerman.net/questions",
"issues": "https://github.com/webman-php/console/issues",
"source": "https://github.com/webman-php/console",
"wiki": "http://www.workerman.net/doc/webman"
},
"time": "2022-07-01T08:59:02+00:00"
},
{ {
"name": "webman/think-cache", "name": "webman/think-cache",
"version": "v1.0.1", "version": "v1.0.1",
...@@ -3771,16 +3823,16 @@ ...@@ -3771,16 +3823,16 @@
}, },
{ {
"name": "workerman/webman-framework", "name": "workerman/webman-framework",
"version": "v1.3.12", "version": "v1.4.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/walkor/webman-framework.git", "url": "https://github.com/walkor/webman-framework.git",
"reference": "a5b392e68a88993e2c94f73805630458b6058c01" "reference": "0f4d5b6c58823656bdc9603f762d4be6e41ae380"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/walkor/webman-framework/zipball/a5b392e68a88993e2c94f73805630458b6058c01", "url": "https://api.github.com/repos/walkor/webman-framework/zipball/0f4d5b6c58823656bdc9603f762d4be6e41ae380",
"reference": "a5b392e68a88993e2c94f73805630458b6058c01", "reference": "0f4d5b6c58823656bdc9603f762d4be6e41ae380",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
...@@ -3838,7 +3890,7 @@ ...@@ -3838,7 +3890,7 @@
"type": "patreon" "type": "patreon"
} }
], ],
"time": "2022-04-28T12:25:46+00:00" "time": "2022-08-15T12:35:14+00:00"
}, },
{ {
"name": "workerman/workerman", "name": "workerman/workerman",
......
<?php
return [
'enable' => true,
'phar_file_output_dir' => BASE_PATH . DIRECTORY_SEPARATOR . 'build',
'phar_filename' => 'webman.phar',
'signature_algorithm'=> Phar::SHA256, //set the signature algorithm for a phar and apply it. The signature algorithm must be one of Phar::MD5, Phar::SHA1, Phar::SHA256, Phar::SHA512, or Phar::OPENSSL.
'private_key_file' => '', // The file path for certificate or OpenSSL private key file.
//'exclude_pattern' => '#^(?!.*(config/plugin/webman/console/app.php|webman/console/src/Commands/(PharPackCommand.php|ReloadCommand.php)|LICENSE|composer.json|.github|.idea|doc|docs|.git|.setting|runtime|test|test_old|tests|Tests|vendor-bin|.md))(.*)$#',
'exclude_files' => [
'.env', 'LICENSE', 'composer.json', 'composer.lock','start.php'
]
];
...@@ -7,8 +7,5 @@ INSERT INTO `category` VALUES (1, '生活', 1, '2022-04-16 20:54:11', NULL, 0); ...@@ -7,8 +7,5 @@ INSERT INTO `category` VALUES (1, '生活', 1, '2022-04-16 20:54:11', NULL, 0);
INSERT INTO `category` VALUES (2, '技术', 1, '2022-04-16 20:54:11', NULL, 0); INSERT INTO `category` VALUES (2, '技术', 1, '2022-04-16 20:54:11', NULL, 0);
INSERT INTO `category` VALUES (3, '折腾', 1, '2022-04-16 20:54:11', NULL, 0); INSERT INTO `category` VALUES (3, '折腾', 1, '2022-04-16 20:54:11', NULL, 0);
INSERT INTO `article` VALUES (1, '蒹葭', '蒹葭苍苍,白露为霜。所谓伊人,在水一方。溯洄从之,道阻且长。溯游从之,宛在水中央。\n蒹葭萋萋,白露未晞。所谓伊人,在水之湄。溯洄从之,道阻且跻。溯游从之,宛在水中坻。\n蒹葭采采,白露未已。所谓伊人,在', 1, '/upload/20220517/dip1652765664FSjzHW.jpg', '蒹葭苍苍,白露为霜。所谓伊人,在水一方。溯洄从之,道阻且长。溯游从之,宛在水中央。<br>\n蒹葭萋萋,白露未晞。所谓伊人,在水之湄。溯洄从之,道阻且跻。溯游从之,宛在水中坻。<br>\n蒹葭采采,白露未已。所谓伊人,在水之涘。溯洄从之,道阻且右。溯游从之,宛在水中沚。<br>', '2022-05-08', 11, 1, 0, '2022-05-08 15:55:46', '2022-05-17 13:34:29'); INSERT INTO `article` VALUES (1, '蒹葭', '蒹葭苍苍,白露为霜。所谓伊人,在水一方。溯洄从之,道阻且长。溯游从之,宛在水中央。\n蒹葭萋萋,白露未晞。所谓伊人,在水之湄。溯洄从之,道阻且跻。溯游从之,宛在水中坻。\n蒹葭采采,白露未已。所谓伊人,在', 1, '/upload/20220517/dip1652765664FSjzHW.jpg', '蒹葭苍苍,白露为霜。所谓伊人,在水一方。溯洄从之,道阻且长。溯游从之,宛在水中央。<br>\n蒹葭萋萋,白露未晞。所谓伊人,在水之湄。溯洄从之,道阻且跻。溯游从之,宛在水中坻。<br>\n蒹葭采采,白露未已。所谓伊人,在水之涘。溯洄从之,道阻且右。溯游从之,宛在水中沚。<br>', '2022-05-08', 11, 1, 0, '2022-05-08 15:55:46', '2022-05-17 13:34:29');
INSERT INTO `article` VALUES (2, '值得收藏的一份MySQL规范', '本文档是为帮助研发与运维人员按照规范使用MySQL数据库,提升研发写SQL的水平。致力于提供一个安全,稳定,高性能的数据库环境。\n命名规范\n\n1) 库名、表名、字段名必须使用小写字母,\"_\"分割。', 2, '', '<div class=\"post\" style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial;\">\n<div class=\"single viewall\" id=\"article_content\" style=\"margin: 0px; padding: 5px 0px; border-width: 1px 0px 0px; border-top-style: dotted; border-right-style: initial; border-bottom-style: initial; border-left-style: initial; border-top-color: rgb(24, 24, 27); border-right-color: initial; border-bottom-color: initial; border-left-color: initial; border-image: initial; vertical-align: baseline; line-height: 30px; overflow-wrap: break-word; word-break: break-all; overflow: hidden; position: relative;\">\n<p style=\"margin-bottom: 1em; padding: 0px; border: 0px; vertical-align: baseline; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">本文档是为帮助研发与运维人员按照规范使用MySQL数据库,提升研发写SQL的水平。致力于提供一个安全,稳定,高性能的数据库环境。</span></p>\n<h2 style=\"margin-top: 0px; padding: 0px 0px 15px; border-top: 0px; border-right: 0px; border-left: 0px; border-bottom-color: rgb(24, 24, 27); border-image: initial; vertical-align: baseline; line-height: 1.5; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">命名规范</span></h2>\n<blockquote style=\"background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; margin: 0px 0px 20px; padding: 10px 20px 10px 50px; border: 0px; vertical-align: baseline; line-height: 1.8; border-radius: 3px; position: relative;\">\n<p style=\"padding: 0px; border: 0px; vertical-align: baseline; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">1) 库名、表名、字段名必须使用小写字母,\"_\"分割。<br style=\"margin: 0px; padding: 0px;\">\n2) 库名、表名、字段名不超过12个字符。<br style=\"margin: 0px; padding: 0px;\">\n3) 库名、表名、字段名禁止使用MySQL保留字,见附件。<br style=\"margin: 0px; padding: 0px;\">\n4) 库名、表名、字段名见名知意,建议使用名词而不是动词。<br style=\"margin: 0px; padding: 0px;\">\n5) 数据对象、变量的命名都采用英文字符,禁止使用中文命名。<br style=\"margin: 0px; padding: 0px;\">\n6) 临时库、表名必须以tmp为前缀,并以日期为后缀。<br style=\"margin: 0px; padding: 0px;\">\n7) 备份库、表必须以bak为前缀,并以日期为后缀。</span></p>\n</blockquote>\n<h2 style=\"margin-top: 0px; padding: 0px 0px 15px; border-top: 0px; border-right: 0px; border-left: 0px; border-bottom-color: rgb(24, 24, 27); border-image: initial; vertical-align: baseline; line-height: 1.5; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">基础规范</span></h2>\n<blockquote style=\"background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; margin: 0px 0px 20px; padding: 10px 20px 10px 50px; border: 0px; vertical-align: baseline; line-height: 1.8; border-radius: 3px; position: relative;\">\n<p style=\"padding: 0px; border: 0px; vertical-align: baseline; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">1) 所有表统一使用InnoDB存储引擎。<br style=\"margin: 0px; padding: 0px;\">\n2) 表字符集选择UTF8mb4。<br style=\"margin: 0px; padding: 0px;\">\n3) 所有表和列都需要添加注释。<br style=\"margin: 0px; padding: 0px;\">\n4) 禁止在数据库中存储图片、文件。<br style=\"margin: 0px; padding: 0px;\">\n5) 禁止在线上做数据库压力测试,如有特殊需要,需提前报备。<br style=\"margin: 0px; padding: 0px;\">\n6) 禁止客户端直接操作测试,生产数据库。<br style=\"margin: 0px; padding: 0px;\">\n7) 研发保证应用与数据库表结构版本的统一,并提供相应的数据库回滚策略。<br style=\"margin: 0px; padding: 0px;\">\n8) 表结构变更DBA审核未通过的,不允许上线。</span></p>\n</blockquote>\n<h2 style=\"margin-top: 0px; padding: 0px 0px 15px; border-top: 0px; border-right: 0px; border-left: 0px; border-bottom-color: rgb(24, 24, 27); border-image: initial; vertical-align: baseline; line-height: 1.5; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">字段设计规范</span></h2>\n<blockquote style=\"background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; margin: 0px 0px 20px; padding: 10px 20px 10px 50px; border: 0px; vertical-align: baseline; line-height: 1.8; border-radius: 3px; position: relative;\">\n<p style=\"padding: 0px; border: 0px; vertical-align: baseline; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">1) 每张表必须有整型主键。如:id bigint(20) UNSIGNED , NOT NULL,不要自增。<br style=\"margin: 0px; padding: 0px;\">\n2) 禁止DEFAULT NULL,建议NOT NULL 设置默认值。<br style=\"margin: 0px; padding: 0px;\">\n3) 存储精确浮点数必须使用DECIMAL替代FLOAT和DOUBLE,或者使用bigint(需要做转换)。<br style=\"margin: 0px; padding: 0px;\">\n4) 建议使用UNSIGNED存储非负数值。<br style=\"margin: 0px; padding: 0px;\">\n5) 不建议使用ENUM类型,使用TINYINT来代替。<br style=\"margin: 0px; padding: 0px;\">\n6) 建议使用INT UNSIGNED存储IPV4。<br style=\"margin: 0px; padding: 0px;\">\n7) 禁止在数据库中存储明文密码。<br style=\"margin: 0px; padding: 0px;\">\n8) 整形定义中建议采用INT(10),而不是INT(1),INT(11)或其他。<br style=\"margin: 0px; padding: 0px;\">\n9) 存储状态,性别等,用TINYINT。<br style=\"margin: 0px; padding: 0px;\">\n10) 将过大字段拆分到其他表中。尽可能不使用TEXT、BLOB类型。如果必须使用,业务表中的TEXT,BLOB中字段,必须要拆分到单独的表中存储。<br style=\"margin: 0px; padding: 0px;\">\n11) 需要根据实际的宽度来选择VARCHAR(N)类型的宽度。<br style=\"margin: 0px; padding: 0px;\">\n12) N表示的是字符数不是字节数. VARCHAR(N),N尽可能小,进行排序和创建临时表一类的内存操作时,会使用N的长度申请内存。<br style=\"margin: 0px; padding: 0px;\">\n13) 存储年使用YEAR类型,存储日期使用DATE类型。&nbsp;<br style=\"margin: 0px; padding: 0px;\">\n14) 13 存储时间(精确到秒)建议使用TIMESTAMP类型,因为TIMESTAMP使用4字节,DATETIME使用8个字节。TIMESTAMP类型保存的值不能比1970早或比2037晚。</span></p>\n</blockquote>\n<h2 style=\"margin-top: 0px; padding: 0px 0px 15px; border-top: 0px; border-right: 0px; border-left: 0px; border-bottom-color: rgb(24, 24, 27); border-image: initial; vertical-align: baseline; line-height: 1.5; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">一句话总结:</span></h2>\n<blockquote style=\"background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; margin: 0px 0px 20px; padding: 10px 20px 10px 50px; border: 0px; vertical-align: baseline; line-height: 1.8; border-radius: 3px; position: relative;\">\n<p dir=\"ltr\" style=\"padding: 0px; border: 0px; vertical-align: baseline; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">能NOT NULL 就NOT NULL,char、varchar用NOT NULL DEFAULT \'\',tinyint、smallint、int用NOT NULL DEFAULT 0。<br style=\"margin: 0px; padding: 0px;\">\nchar、varchar取值要吝啬,根据实际需求给,比如人名一般不超过5个,varchar(5),不要varchar(200)。int、tinyint这类,int(1)和int(13)都是一样的,<br style=\"margin: 0px; padding: 0px;\">\n我们统一用int(10),tinyint取值范围[-128,127],加了unsigned取值[0,255],如果不需要存储负数,整型类型的加unsigned。</span></p>\n</blockquote>\n<h2 style=\"margin-top: 0px; padding: 0px 0px 15px; border-top: 0px; border-right: 0px; border-left: 0px; border-bottom-color: rgb(24, 24, 27); border-image: initial; vertical-align: baseline; line-height: 1.5; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">索引规范</span></h2>\n<blockquote style=\"background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; margin: 0px 0px 20px; padding: 10px 20px 10px 50px; border: 0px; vertical-align: baseline; line-height: 1.8; border-radius: 3px; position: relative;\">\n<p style=\"padding: 0px; border: 0px; vertical-align: baseline; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">1) 单张表的索引数量控制在5个以内。<br style=\"margin: 0px; padding: 0px;\">\n2) 复合索引中的字段数建议不超过5个。<br style=\"margin: 0px; padding: 0px;\">\n3) 非唯一索引必须按照\"idx_字段名称_字段名称[_字段名]\"进行命名。<br style=\"margin: 0px; padding: 0px;\">\n4) 唯一索引必须按照\"uniq_字段名称_字段名称[_字段名]\"进行命名。<br style=\"margin: 0px; padding: 0px;\">\n5) 合理利用覆盖索引。不使用更新频繁的列做为索引。<br style=\"margin: 0px; padding: 0px;\">\n6) 对长字符串考虑使用前缀索引,前缀索引长度不超过8个字符。<br style=\"margin: 0px; padding: 0px;\">\n7) 索引字段的顺序需要考虑字段值去重之后的个数,个数多的放在前面。<br style=\"margin: 0px; padding: 0px;\">\n8) 使用EXPLAIN判断SQL语句是否合理使用索引,尽量避免extra列出现:Using File Sort,UsingTemporary。<br style=\"margin: 0px; padding: 0px;\">\n9) UPDATE、DELETE语句需要根据WHERE条件添加索引。<br style=\"margin: 0px; padding: 0px;\">\n10) 合理创建联合索引(避免冗余),(a,b,c) 相当于 (a) 、(a,b) 、(a,b,c),但(a,c)只能用到部分索引。</span></p>\n</blockquote>\n<h2 style=\"margin-top: 0px; padding: 0px 0px 15px; border-top: 0px; border-right: 0px; border-left: 0px; border-bottom-color: rgb(24, 24, 27); border-image: initial; vertical-align: baseline; line-height: 1.5; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">索引禁忌</span></h2>\n<blockquote style=\"background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; margin: 0px 0px 20px; padding: 10px 20px 10px 50px; border: 0px; vertical-align: baseline; line-height: 1.8; border-radius: 3px; position: relative;\">\n<p style=\"padding: 0px; border: 0px; vertical-align: baseline; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">1) 不在选择性低的列上建立索引,例如\"性别\", \"状态\"\"类型\"。<br style=\"margin: 0px; padding: 0px;\">\n2) 不在索引列进行数学运算和函数运算。<br style=\"margin: 0px; padding: 0px;\">\n3) 尽量不使用外键。<br style=\"margin: 0px; padding: 0px;\">\n4) 高并发场景不建议使用唯一索引。<br style=\"margin: 0px; padding: 0px;\">\n5) 不使用前导查询,如like \"%ab\",like \"%ab%\"。<br style=\"margin: 0px; padding: 0px;\">\n6 SQL语句规范<br style=\"margin: 0px; padding: 0px;\">\n1) SQL语句中IN包含的值不应过多(不超过1000个)<br style=\"margin: 0px; padding: 0px;\">\n2) UPDATE、DELETE语句不使用LIMIT。<br style=\"margin: 0px; padding: 0px;\">\n3) WHERE条件中必须使用合适的类型,避免MySQL进行隐式类型转化。<br style=\"margin: 0px; padding: 0px;\">\n4) SELECT语句只获取需要的字段。<br style=\"margin: 0px; padding: 0px;\">\n5) SELECT、INSERT语句必须显式的指明字段名称,不使用SELECT *,不使用INSERT INTO table()。<br style=\"margin: 0px; padding: 0px;\">\n6) WHERE条件中的非等值条件(IN、BETWEEN、&lt;、&lt;=、&gt;、&gt;=)会导致后面的条件使用不了索引。<br style=\"margin: 0px; padding: 0px;\">\n7) 避免在SQL语句进行数学运算或者函数运算,容易将业务逻辑和DB耦合在一起。<br style=\"margin: 0px; padding: 0px;\">\n8) INSERT语句使用batch提交(INSERT INTO table VALUES(),(),()……),values的个数不应过多。<br style=\"margin: 0px; padding: 0px;\">\n9) 避免使用存储过程、触发器、函数等,容易将业务逻辑和DB耦合在一起,并且MySQL的存储过程、触发器、函数中存在一定的bug。<br style=\"margin: 0px; padding: 0px;\">\n10) 避免使用JOIN。<br style=\"margin: 0px; padding: 0px;\">\n11) 使用合理的SQL语句减少与数据库的交互次数。<br style=\"margin: 0px; padding: 0px;\">\n12) 不使用ORDER BY RAND(),使用其他方法替换。<br style=\"margin: 0px; padding: 0px;\">\n13) 建议使用合理的分页方式以提高分页的效率。<br style=\"margin: 0px; padding: 0px;\">\n14) 统计表中记录数时使用COUNT(*),而不是COUNT(primary_key)和COUNT(1)。</span></p>\n</blockquote></div>\n</div>', '2022-05-17', 6, 1, 0, '2022-05-17 13:37:28', '2022-05-17 13:37:56'); INSERT INTO `article` VALUES (2, '我承认我找不到素材了', '那就这样吧!\n\n\n\n', 3, '', '那就这样吧!\n<div><br>\n</div>\n<div align=\"center\"><img src=\"/upload/20220517/Hkb1652765942zWOqaJ.jpg\"><br>\n</div>', '2022-05-17', 11, 1, 0, '2022-05-17 13:39:04', '2022-05-17 13:41:21');
INSERT INTO `article` VALUES (3, '我承认我找不到素材了', '那就这样吧!\n\n\n\n', 3, '', '那就这样吧!\n<div><br>\n</div>\n<div align=\"center\"><img src=\"/upload/20220517/Hkb1652765942zWOqaJ.jpg\"><br>\n</div>', '2022-05-17', 11, 1, 0, '2022-05-17 13:39:04', '2022-05-17 13:41:21'); INSERT INTO `banner` VALUES (1, '轮播图可以后台设置', '', 0, '', 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic1.win4000.com%2Fwallpaper%2F2020-03-16%2F5e6f456284b3e.jpg&refer=http%3A%2F%2Fpic1.win4000.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1664443024&t=56aed7f75b80334354600cd8556d093c', 1, NULL, NULL, 1);
INSERT INTO `article` VALUES (1, '蒹葭', '蒹葭苍苍,白露为霜。所谓伊人,在水一方。溯洄从之,道阻且长。溯游从之,宛在水中央。\n蒹葭萋萋,白露未晞。所谓伊人,在水之湄。溯洄从之,道阻且跻。溯游从之,宛在水中坻。\n蒹葭采采,白露未已。所谓伊人,在', 1, '/upload/20220517/dip1652765664FSjzHW.jpg', '蒹葭苍苍,白露为霜。所谓伊人,在水一方。溯洄从之,道阻且长。溯游从之,宛在水中央。<br>\n蒹葭萋萋,白露未晞。所谓伊人,在水之湄。溯洄从之,道阻且跻。溯游从之,宛在水中坻。<br>\n蒹葭采采,白露未已。所谓伊人,在水之涘。溯洄从之,道阻且右。溯游从之,宛在水中沚。<br>', '2022-05-08', 11, 1, 0, '2022-05-08 15:55:46', '2022-05-17 13:34:29'); \ No newline at end of file
INSERT INTO `article` VALUES (2, '值得收藏的一份MySQL规范', '本文档是为帮助研发与运维人员按照规范使用MySQL数据库,提升研发写SQL的水平。致力于提供一个安全,稳定,高性能的数据库环境。\n命名规范\n\n1) 库名、表名、字段名必须使用小写字母,\"_\"分割。', 2, '', '<div class=\"post\" style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial;\">\n<div class=\"single viewall\" id=\"article_content\" style=\"margin: 0px; padding: 5px 0px; border-width: 1px 0px 0px; border-top-style: dotted; border-right-style: initial; border-bottom-style: initial; border-left-style: initial; border-top-color: rgb(24, 24, 27); border-right-color: initial; border-bottom-color: initial; border-left-color: initial; border-image: initial; vertical-align: baseline; line-height: 30px; overflow-wrap: break-word; word-break: break-all; overflow: hidden; position: relative;\">\n<p style=\"margin-bottom: 1em; padding: 0px; border: 0px; vertical-align: baseline; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">本文档是为帮助研发与运维人员按照规范使用MySQL数据库,提升研发写SQL的水平。致力于提供一个安全,稳定,高性能的数据库环境。</span></p>\n<h2 style=\"margin-top: 0px; padding: 0px 0px 15px; border-top: 0px; border-right: 0px; border-left: 0px; border-bottom-color: rgb(24, 24, 27); border-image: initial; vertical-align: baseline; line-height: 1.5; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">命名规范</span></h2>\n<blockquote style=\"background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; margin: 0px 0px 20px; padding: 10px 20px 10px 50px; border: 0px; vertical-align: baseline; line-height: 1.8; border-radius: 3px; position: relative;\">\n<p style=\"padding: 0px; border: 0px; vertical-align: baseline; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">1) 库名、表名、字段名必须使用小写字母,\"_\"分割。<br style=\"margin: 0px; padding: 0px;\">\n2) 库名、表名、字段名不超过12个字符。<br style=\"margin: 0px; padding: 0px;\">\n3) 库名、表名、字段名禁止使用MySQL保留字,见附件。<br style=\"margin: 0px; padding: 0px;\">\n4) 库名、表名、字段名见名知意,建议使用名词而不是动词。<br style=\"margin: 0px; padding: 0px;\">\n5) 数据对象、变量的命名都采用英文字符,禁止使用中文命名。<br style=\"margin: 0px; padding: 0px;\">\n6) 临时库、表名必须以tmp为前缀,并以日期为后缀。<br style=\"margin: 0px; padding: 0px;\">\n7) 备份库、表必须以bak为前缀,并以日期为后缀。</span></p>\n</blockquote>\n<h2 style=\"margin-top: 0px; padding: 0px 0px 15px; border-top: 0px; border-right: 0px; border-left: 0px; border-bottom-color: rgb(24, 24, 27); border-image: initial; vertical-align: baseline; line-height: 1.5; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">基础规范</span></h2>\n<blockquote style=\"background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; margin: 0px 0px 20px; padding: 10px 20px 10px 50px; border: 0px; vertical-align: baseline; line-height: 1.8; border-radius: 3px; position: relative;\">\n<p style=\"padding: 0px; border: 0px; vertical-align: baseline; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">1) 所有表统一使用InnoDB存储引擎。<br style=\"margin: 0px; padding: 0px;\">\n2) 表字符集选择UTF8mb4。<br style=\"margin: 0px; padding: 0px;\">\n3) 所有表和列都需要添加注释。<br style=\"margin: 0px; padding: 0px;\">\n4) 禁止在数据库中存储图片、文件。<br style=\"margin: 0px; padding: 0px;\">\n5) 禁止在线上做数据库压力测试,如有特殊需要,需提前报备。<br style=\"margin: 0px; padding: 0px;\">\n6) 禁止客户端直接操作测试,生产数据库。<br style=\"margin: 0px; padding: 0px;\">\n7) 研发保证应用与数据库表结构版本的统一,并提供相应的数据库回滚策略。<br style=\"margin: 0px; padding: 0px;\">\n8) 表结构变更DBA审核未通过的,不允许上线。</span></p>\n</blockquote>\n<h2 style=\"margin-top: 0px; padding: 0px 0px 15px; border-top: 0px; border-right: 0px; border-left: 0px; border-bottom-color: rgb(24, 24, 27); border-image: initial; vertical-align: baseline; line-height: 1.5; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">字段设计规范</span></h2>\n<blockquote style=\"background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; margin: 0px 0px 20px; padding: 10px 20px 10px 50px; border: 0px; vertical-align: baseline; line-height: 1.8; border-radius: 3px; position: relative;\">\n<p style=\"padding: 0px; border: 0px; vertical-align: baseline; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">1) 每张表必须有整型主键。如:id bigint(20) UNSIGNED , NOT NULL,不要自增。<br style=\"margin: 0px; padding: 0px;\">\n2) 禁止DEFAULT NULL,建议NOT NULL 设置默认值。<br style=\"margin: 0px; padding: 0px;\">\n3) 存储精确浮点数必须使用DECIMAL替代FLOAT和DOUBLE,或者使用bigint(需要做转换)。<br style=\"margin: 0px; padding: 0px;\">\n4) 建议使用UNSIGNED存储非负数值。<br style=\"margin: 0px; padding: 0px;\">\n5) 不建议使用ENUM类型,使用TINYINT来代替。<br style=\"margin: 0px; padding: 0px;\">\n6) 建议使用INT UNSIGNED存储IPV4。<br style=\"margin: 0px; padding: 0px;\">\n7) 禁止在数据库中存储明文密码。<br style=\"margin: 0px; padding: 0px;\">\n8) 整形定义中建议采用INT(10),而不是INT(1),INT(11)或其他。<br style=\"margin: 0px; padding: 0px;\">\n9) 存储状态,性别等,用TINYINT。<br style=\"margin: 0px; padding: 0px;\">\n10) 将过大字段拆分到其他表中。尽可能不使用TEXT、BLOB类型。如果必须使用,业务表中的TEXT,BLOB中字段,必须要拆分到单独的表中存储。<br style=\"margin: 0px; padding: 0px;\">\n11) 需要根据实际的宽度来选择VARCHAR(N)类型的宽度。<br style=\"margin: 0px; padding: 0px;\">\n12) N表示的是字符数不是字节数. VARCHAR(N),N尽可能小,进行排序和创建临时表一类的内存操作时,会使用N的长度申请内存。<br style=\"margin: 0px; padding: 0px;\">\n13) 存储年使用YEAR类型,存储日期使用DATE类型。&nbsp;<br style=\"margin: 0px; padding: 0px;\">\n14) 13 存储时间(精确到秒)建议使用TIMESTAMP类型,因为TIMESTAMP使用4字节,DATETIME使用8个字节。TIMESTAMP类型保存的值不能比1970早或比2037晚。</span></p>\n</blockquote>\n<h2 style=\"margin-top: 0px; padding: 0px 0px 15px; border-top: 0px; border-right: 0px; border-left: 0px; border-bottom-color: rgb(24, 24, 27); border-image: initial; vertical-align: baseline; line-height: 1.5; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">一句话总结:</span></h2>\n<blockquote style=\"background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; margin: 0px 0px 20px; padding: 10px 20px 10px 50px; border: 0px; vertical-align: baseline; line-height: 1.8; border-radius: 3px; position: relative;\">\n<p dir=\"ltr\" style=\"padding: 0px; border: 0px; vertical-align: baseline; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">能NOT NULL 就NOT NULL,char、varchar用NOT NULL DEFAULT \'\',tinyint、smallint、int用NOT NULL DEFAULT 0。<br style=\"margin: 0px; padding: 0px;\">\nchar、varchar取值要吝啬,根据实际需求给,比如人名一般不超过5个,varchar(5),不要varchar(200)。int、tinyint这类,int(1)和int(13)都是一样的,<br style=\"margin: 0px; padding: 0px;\">\n我们统一用int(10),tinyint取值范围[-128,127],加了unsigned取值[0,255],如果不需要存储负数,整型类型的加unsigned。</span></p>\n</blockquote>\n<h2 style=\"margin-top: 0px; padding: 0px 0px 15px; border-top: 0px; border-right: 0px; border-left: 0px; border-bottom-color: rgb(24, 24, 27); border-image: initial; vertical-align: baseline; line-height: 1.5; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">索引规范</span></h2>\n<blockquote style=\"background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; margin: 0px 0px 20px; padding: 10px 20px 10px 50px; border: 0px; vertical-align: baseline; line-height: 1.8; border-radius: 3px; position: relative;\">\n<p style=\"padding: 0px; border: 0px; vertical-align: baseline; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">1) 单张表的索引数量控制在5个以内。<br style=\"margin: 0px; padding: 0px;\">\n2) 复合索引中的字段数建议不超过5个。<br style=\"margin: 0px; padding: 0px;\">\n3) 非唯一索引必须按照\"idx_字段名称_字段名称[_字段名]\"进行命名。<br style=\"margin: 0px; padding: 0px;\">\n4) 唯一索引必须按照\"uniq_字段名称_字段名称[_字段名]\"进行命名。<br style=\"margin: 0px; padding: 0px;\">\n5) 合理利用覆盖索引。不使用更新频繁的列做为索引。<br style=\"margin: 0px; padding: 0px;\">\n6) 对长字符串考虑使用前缀索引,前缀索引长度不超过8个字符。<br style=\"margin: 0px; padding: 0px;\">\n7) 索引字段的顺序需要考虑字段值去重之后的个数,个数多的放在前面。<br style=\"margin: 0px; padding: 0px;\">\n8) 使用EXPLAIN判断SQL语句是否合理使用索引,尽量避免extra列出现:Using File Sort,UsingTemporary。<br style=\"margin: 0px; padding: 0px;\">\n9) UPDATE、DELETE语句需要根据WHERE条件添加索引。<br style=\"margin: 0px; padding: 0px;\">\n10) 合理创建联合索引(避免冗余),(a,b,c) 相当于 (a) 、(a,b) 、(a,b,c),但(a,c)只能用到部分索引。</span></p>\n</blockquote>\n<h2 style=\"margin-top: 0px; padding: 0px 0px 15px; border-top: 0px; border-right: 0px; border-left: 0px; border-bottom-color: rgb(24, 24, 27); border-image: initial; vertical-align: baseline; line-height: 1.5; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">索引禁忌</span></h2>\n<blockquote style=\"background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; margin: 0px 0px 20px; padding: 10px 20px 10px 50px; border: 0px; vertical-align: baseline; line-height: 1.8; border-radius: 3px; position: relative;\">\n<p style=\"padding: 0px; border: 0px; vertical-align: baseline; position: relative;\"><span style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: baseline;\">1) 不在选择性低的列上建立索引,例如\"性别\", \"状态\"\"类型\"。<br style=\"margin: 0px; padding: 0px;\">\n2) 不在索引列进行数学运算和函数运算。<br style=\"margin: 0px; padding: 0px;\">\n3) 尽量不使用外键。<br style=\"margin: 0px; padding: 0px;\">\n4) 高并发场景不建议使用唯一索引。<br style=\"margin: 0px; padding: 0px;\">\n5) 不使用前导查询,如like \"%ab\",like \"%ab%\"。<br style=\"margin: 0px; padding: 0px;\">\n6 SQL语句规范<br style=\"margin: 0px; padding: 0px;\">\n1) SQL语句中IN包含的值不应过多(不超过1000个)<br style=\"margin: 0px; padding: 0px;\">\n2) UPDATE、DELETE语句不使用LIMIT。<br style=\"margin: 0px; padding: 0px;\">\n3) WHERE条件中必须使用合适的类型,避免MySQL进行隐式类型转化。<br style=\"margin: 0px; padding: 0px;\">\n4) SELECT语句只获取需要的字段。<br style=\"margin: 0px; padding: 0px;\">\n5) SELECT、INSERT语句必须显式的指明字段名称,不使用SELECT *,不使用INSERT INTO table()。<br style=\"margin: 0px; padding: 0px;\">\n6) WHERE条件中的非等值条件(IN、BETWEEN、&lt;、&lt;=、&gt;、&gt;=)会导致后面的条件使用不了索引。<br style=\"margin: 0px; padding: 0px;\">\n7) 避免在SQL语句进行数学运算或者函数运算,容易将业务逻辑和DB耦合在一起。<br style=\"margin: 0px; padding: 0px;\">\n8) INSERT语句使用batch提交(INSERT INTO table VALUES(),(),()……),values的个数不应过多。<br style=\"margin: 0px; padding: 0px;\">\n9) 避免使用存储过程、触发器、函数等,容易将业务逻辑和DB耦合在一起,并且MySQL的存储过程、触发器、函数中存在一定的bug。<br style=\"margin: 0px; padding: 0px;\">\n10) 避免使用JOIN。<br style=\"margin: 0px; padding: 0px;\">\n11) 使用合理的SQL语句减少与数据库的交互次数。<br style=\"margin: 0px; padding: 0px;\">\n12) 不使用ORDER BY RAND(),使用其他方法替换。<br style=\"margin: 0px; padding: 0px;\">\n13) 建议使用合理的分页方式以提高分页的效率。<br style=\"margin: 0px; padding: 0px;\">\n14) 统计表中记录数时使用COUNT(*),而不是COUNT(primary_key)和COUNT(1)。</span></p>\n</blockquote></div>\n</div>', '2022-05-17', 6, 1, 0, '2022-05-17 13:37:28', '2022-05-17 13:37:56');
INSERT INTO `article` VALUES (3, '我承认我找不到素材了', '那就这样吧!\n\n\n\n', 3, '', '那就这样吧!\n<div><br>\n</div>\n<div align=\"center\"><img src=\"/upload/20220517/Hkb1652765942zWOqaJ.jpg\"><br>\n</div>', '2022-05-17', 11, 1, 0, '2022-05-17 13:39:04', '2022-05-17 13:41:21');
\ No newline at end of file
#!/usr/bin/env php #!/usr/bin/env php
<?php <?php
require_once __DIR__ . '/vendor/autoload.php'; require_once __DIR__ . '/vendor/autoload.php';
Support\App::run();
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 (property_exists(Worker::class, 'stopTimeout')) {
Worker::$stopTimeout = $config['stop_timeout'] ?? 2;
}
if ($config['listen']) {
$worker = new Worker($config['listen'], $config['context']);
$property_map = [
'name',
'count',
'user',
'group',
'reusePort',
'transport',
'protocol'
];
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();
...@@ -13,10 +13,12 @@ ...@@ -13,10 +13,12 @@
*/ */
use Dotenv\Dotenv; use Dotenv\Dotenv;
use support\Container; use support\Log;
use Webman\Bootstrap;
use Webman\Config; use Webman\Config;
use Webman\Route; use Webman\Route;
use Webman\Middleware; use Webman\Middleware;
use Webman\Util;
$worker = $worker ?? null; $worker = $worker ?? null;
...@@ -24,7 +26,7 @@ if ($timezone = config('app.default_timezone')) { ...@@ -24,7 +26,7 @@ if ($timezone = config('app.default_timezone')) {
date_default_timezone_set($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) { if (error_reporting() & $level) {
throw new ErrorException($message, 0, $level, $file, $line); throw new ErrorException($message, 0, $level, $file, $line);
} }
...@@ -46,45 +48,85 @@ if (class_exists('Dotenv\Dotenv') && file_exists(base_path() . '/.env')) { ...@@ -46,45 +48,85 @@ if (class_exists('Dotenv\Dotenv') && file_exists(base_path() . '/.env')) {
} }
} }
Config::reload(config_path(), ['route', 'container']); Support\App::loadAllConfig(['route']);
foreach (config('autoload.files', []) as $file) {
include_once $file;
}
foreach (config('plugin', []) as $firm => $projects) { foreach (config('plugin', []) as $firm => $projects) {
foreach ($projects as $name => $project) { foreach ($projects as $name => $project) {
if (!is_array($project)) {
continue;
}
foreach ($project['autoload']['files'] ?? [] as $file) { foreach ($project['autoload']['files'] ?? [] as $file) {
include_once $file; include_once $file;
} }
} }
foreach ($projects['autoload']['files'] ?? [] as $file) {
include_once $file;
}
} }
foreach (config('autoload.files', []) as $file) { Middleware::load(config('middleware', []), '');
include_once $file;
}
$container = Container::instance();
Route::container($container);
Middleware::container($container);
Middleware::load(config('middleware', []));
foreach (config('plugin', []) as $firm => $projects) { foreach (config('plugin', []) as $firm => $projects) {
foreach ($projects as $name => $project) { 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) { 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); $class_name::start($worker);
} }
foreach (config('plugin', []) as $firm => $projects) { foreach (config('plugin', []) as $firm => $projects) {
foreach ($projects as $name => $project) { foreach ($projects as $name => $project) {
if (!is_array($project)) {
continue;
}
foreach ($project['bootstrap'] ?? [] as $class_name) { 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); $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);
}
} }
$directory = base_path() . '/plugin';
$paths = [config_path()];
foreach (Util::scanDir($directory) as $path) {
if (is_dir($path = "$path/config")) {
$paths[] = $path;
}
}
Route::load($paths);
Route::load(config_path());
\ No newline at end of file
...@@ -26,22 +26,22 @@ use Webman\Config; ...@@ -26,22 +26,22 @@ use Webman\Config;
use Webman\Route; use Webman\Route;
// Phar support. // Phar support.
if (is_phar()) { if (\is_phar()) {
define('BASE_PATH', dirname(__DIR__)); \define('BASE_PATH', dirname(__DIR__));
} else { } else {
define('BASE_PATH', realpath(__DIR__ . '/../')); \define('BASE_PATH', realpath(__DIR__ . '/../'));
} }
define('WEBMAN_VERSION', '1.3.0'); \define('WEBMAN_VERSION', '1.4');
/** /**
* @param $return_phar * @param $return_phar
* @return false|string * @return false|string
*/ */
function base_path($return_phar = true) function base_path(bool $return_phar = true)
{ {
static $real_path = ''; static $real_path = '';
if (!$real_path) { if (!$real_path) {
$real_path = is_phar() ? dirname(Phar::running(false)) : BASE_PATH; $real_path = \is_phar() ? \dirname(Phar::running(false)) : BASE_PATH;
} }
return $return_phar ? BASE_PATH : $real_path; return $return_phar ? BASE_PATH : $real_path;
} }
...@@ -61,7 +61,7 @@ function public_path() ...@@ -61,7 +61,7 @@ function public_path()
{ {
static $path = ''; static $path = '';
if (!$path) { if (!$path) {
$path = get_realpath(config('app.public_path', BASE_PATH . DIRECTORY_SEPARATOR . 'public')); $path = \config('app.public_path', BASE_PATH . DIRECTORY_SEPARATOR . 'public');
} }
return $path; return $path;
} }
...@@ -84,30 +84,30 @@ function runtime_path() ...@@ -84,30 +84,30 @@ function runtime_path()
{ {
static $path = ''; static $path = '';
if (!$path) { if (!$path) {
$path = get_realpath(config('app.runtime_path', BASE_PATH . DIRECTORY_SEPARATOR . 'runtime')); $path = \config('app.runtime_path', BASE_PATH . DIRECTORY_SEPARATOR . 'runtime');
} }
return $path; return $path;
} }
/** /**
* @param int $status * @param int $status
* @param array $headers * @param array $headers
* @param string $body * @param string $body
* @return Response * @return Response
*/ */
function response($body = '', $status = 200, $headers = array()) function response($body = '', $status = 200, $headers = [])
{ {
return new Response($status, $headers, $body); return new Response($status, $headers, $body);
} }
/** /**
* @param $data * @param $data
* @param int $options * @param int $options
* @return Response * @return Response
*/ */
function json($data, $options = JSON_UNESCAPED_UNICODE) function json($data, $options = JSON_UNESCAPED_UNICODE)
{ {
return new Response(200, ['Content-Type' => 'application/json'], json_encode($data, $options)); return new Response(200, ['Content-Type' => 'application/json'], \json_encode($data, $options));
} }
/** /**
...@@ -123,25 +123,25 @@ function xml($xml) ...@@ -123,25 +123,25 @@ function xml($xml)
} }
/** /**
* @param $data * @param $data
* @param string $callback_name * @param string $callback_name
* @return Response * @return Response
*/ */
function jsonp($data, $callback_name = 'callback') function jsonp($data, $callback_name = 'callback')
{ {
if (!is_scalar($data) && null !== $data) { if (!\is_scalar($data) && null !== $data) {
$data = json_encode($data); $data = \json_encode($data);
} }
return new Response(200, [], "$callback_name($data)"); return new Response(200, [], "$callback_name($data)");
} }
/** /**
* @param $location * @param string $location
* @param int $status * @param int $status
* @param array $headers * @param array $headers
* @return Response * @return Response
*/ */
function redirect($location, $status = 302, $headers = []) function redirect(string $location, int $status = 302, array $headers = [])
{ {
$response = new Response($status, ['Location' => $location]); $response = new Response($status, ['Location' => $location]);
if (!empty($headers)) { if (!empty($headers)) {
...@@ -151,60 +151,60 @@ function redirect($location, $status = 302, $headers = []) ...@@ -151,60 +151,60 @@ function redirect($location, $status = 302, $headers = [])
} }
/** /**
* @param $template * @param $template
* @param array $vars * @param array $vars
* @param null $app * @param null $app
* @return Response * @return Response
*/ */
function view($template, $vars = [], $app = null) function view(string $template, array $vars = [], string $app = null)
{ {
static $handler; $request = \request();
if (null === $handler) { $plugin = $request->plugin ?? '';
$handler = config('view.handler'); $handler = \config($plugin ? "plugin.$plugin.view.handler" : 'view.handler');
}
return new Response(200, [], $handler::render($template, $vars, $app)); return new Response(200, [], $handler::render($template, $vars, $app));
} }
/** /**
* @param $template * @param string $template
* @param array $vars * @param array $vars
* @param null $app * @param string|null $app
* @return Response * @return Response
* @throws Throwable
*/ */
function raw_view($template, $vars = [], $app = null) function raw_view(string $template, array $vars = [], string $app = null)
{ {
return new Response(200, [], Raw::render($template, $vars, $app)); return new Response(200, [], Raw::render($template, $vars, $app));
} }
/** /**
* @param $template * @param string $template
* @param array $vars * @param array $vars
* @param null $app * @param string|null $app
* @return Response * @return Response
*/ */
function blade_view($template, $vars = [], $app = null) function blade_view(string $template, array $vars = [], string $app = null)
{ {
return new Response(200, [], Blade::render($template, $vars, $app)); return new Response(200, [], Blade::render($template, $vars, $app));
} }
/** /**
* @param $template * @param string $template
* @param array $vars * @param array $vars
* @param null $app * @param string|null $app
* @return Response * @return Response
*/ */
function think_view($template, $vars = [], $app = null) function think_view(string $template, array $vars = [], string $app = null)
{ {
return new Response(200, [], ThinkPHP::render($template, $vars, $app)); return new Response(200, [], ThinkPHP::render($template, $vars, $app));
} }
/** /**
* @param $template * @param string $template
* @param array $vars * @param array $vars
* @param null $app * @param string|null $app
* @return Response * @return Response
*/ */
function twig_view($template, $vars = [], $app = null) function twig_view(string $template, array $vars = [], string $app = null)
{ {
return new Response(200, [], Twig::render($template, $vars, $app)); return new Response(200, [], Twig::render($template, $vars, $app));
} }
...@@ -218,21 +218,21 @@ function request() ...@@ -218,21 +218,21 @@ function request()
} }
/** /**
* @param $key * @param string|null $key
* @param null $default * @param $default
* @return mixed * @return array|mixed|null
*/ */
function config($key = null, $default = null) function config(string $key = null, $default = null)
{ {
return Config::get($key, $default); return Config::get($key, $default);
} }
/** /**
* @param $name * @param string $name
* @param ...$parameters * @param ...$parameters
* @return string * @return string
*/ */
function route($name, ...$parameters) function route(string $name, ...$parameters)
{ {
$route = Route::getByName($name); $route = Route::getByName($name);
if (!$route) { if (!$route) {
...@@ -243,8 +243,8 @@ function route($name, ...$parameters) ...@@ -243,8 +243,8 @@ function route($name, ...$parameters)
return $route->url(); return $route->url();
} }
if (is_array(current($parameters))) { if (\is_array(\current($parameters))) {
$parameters = current($parameters); $parameters = \current($parameters);
} }
return $route->url($parameters); return $route->url($parameters);
...@@ -257,7 +257,7 @@ function route($name, ...$parameters) ...@@ -257,7 +257,7 @@ function route($name, ...$parameters)
*/ */
function session($key = null, $default = null) function session($key = null, $default = null)
{ {
$session = request()->session(); $session = \request()->session();
if (null === $key) { if (null === $key) {
return $session; return $session;
} }
...@@ -267,7 +267,7 @@ function session($key = null, $default = null) ...@@ -267,7 +267,7 @@ function session($key = null, $default = null)
} }
if (\strpos($key, '.')) { if (\strpos($key, '.')) {
$key_array = \explode('.', $key); $key_array = \explode('.', $key);
$value = $session->all(); $value = $session->all();
foreach ($key_array as $index) { foreach ($key_array as $index) {
if (!isset($value[$index])) { if (!isset($value[$index])) {
return $default; return $default;
...@@ -280,8 +280,8 @@ function session($key = null, $default = null) ...@@ -280,8 +280,8 @@ function session($key = null, $default = null)
} }
/** /**
* @param null|string $id * @param string $id
* @param array $parameters * @param array $parameters
* @param string|null $domain * @param string|null $domain
* @param string|null $locale * @param string|null $locale
* @return string * @return string
...@@ -311,48 +311,50 @@ function locale(string $locale = null) ...@@ -311,48 +311,50 @@ function locale(string $locale = null)
*/ */
function not_found() function not_found()
{ {
return new Response(404, [], file_get_contents(public_path() . '/404.html')); return new Response(404, [], \file_get_contents(public_path() . '/404.html'));
} }
/** /**
* Copy dir. * Copy dir.
* @param $source *
* @param $dest * @param string $source
* @param string $dest
* @param bool $overwrite * @param bool $overwrite
* @return void * @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)) { if (!is_dir($dest)) {
mkdir($dest); \mkdir($dest);
} }
$files = scandir($source); $files = \scandir($source);
foreach ($files as $file) { foreach ($files as $file) {
if ($file !== "." && $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))) { } else if (\file_exists($source) && ($overwrite || !\file_exists($dest))) {
copy($source, $dest); \copy($source, $dest);
} }
} }
/** /**
* Remove dir. * Remove dir.
* @param $dir *
* @param string $dir
* @return bool * @return bool
*/ */
function remove_dir($dir) function remove_dir(string $dir)
{ {
if (is_link($dir) || is_file($dir)) { if (\is_link($dir) || \is_file($dir)) {
return unlink($dir); return \unlink($dir);
} }
$files = array_diff(scandir($dir), array('.', '..')); $files = \array_diff(\scandir($dir), array('.', '..'));
foreach ($files as $file) { 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);
} }
/** /**
...@@ -369,15 +371,15 @@ function worker_bind($worker, $class) ...@@ -369,15 +371,15 @@ function worker_bind($worker, $class)
'onBufferFull', 'onBufferFull',
'onBufferDrain', 'onBufferDrain',
'onWorkerStop', 'onWorkerStop',
'onWebSocketConnect', 'onWebSocketConnect'
]; ];
foreach ($callback_map as $name) { foreach ($callback_map as $name) {
if (method_exists($class, $name)) { if (\method_exists($class, $name)) {
$worker->$name = [$class, $name]; $worker->$name = [$class, $name];
} }
} }
if (method_exists($class, 'onWorkerStart')) { if (\method_exists($class, 'onWorkerStart')) {
call_user_func([$class, 'onWorkerStart'], $worker); [$class, 'onWorkerStart']($worker);
} }
} }
...@@ -388,7 +390,7 @@ function worker_bind($worker, $class) ...@@ -388,7 +390,7 @@ function worker_bind($worker, $class)
*/ */
function worker_start($process_name, $config) function worker_start($process_name, $config)
{ {
$worker = new Worker($config['listen'] ?? null, $config['context'] ?? []); $worker = new Worker($config['listen'] ?? null, $config['context'] ?? []);
$property_map = [ $property_map = [
'count', 'count',
'user', 'user',
...@@ -406,10 +408,10 @@ function worker_start($process_name, $config) ...@@ -406,10 +408,10 @@ function worker_start($process_name, $config)
} }
$worker->onWorkerStart = function ($worker) use ($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) { 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"; echo "process error: class {$server['handler']} not exists\r\n";
continue; continue;
} }
...@@ -418,18 +420,18 @@ function worker_start($process_name, $config) ...@@ -418,18 +420,18 @@ function worker_start($process_name, $config)
echo "listen: {$server['listen']}\n"; echo "listen: {$server['listen']}\n";
} }
$instance = Container::make($server['handler'], $server['constructor'] ?? []); $instance = Container::make($server['handler'], $server['constructor'] ?? []);
worker_bind($listen, $instance); \worker_bind($listen, $instance);
$listen->listen(); $listen->listen();
} }
if (isset($config['handler'])) { if (isset($config['handler'])) {
if (!class_exists($config['handler'])) { if (!\class_exists($config['handler'])) {
echo "process error: class {$config['handler']} not exists\r\n"; echo "process error: class {$config['handler']} not exists\r\n";
return; return;
} }
$instance = Container::make($config['handler'], $config['constructor'] ?? []); $instance = Container::make($config['handler'], $config['constructor'] ?? []);
worker_bind($worker, $instance); \worker_bind($worker, $instance);
} }
}; };
...@@ -444,10 +446,10 @@ function worker_start($process_name, $config) ...@@ -444,10 +446,10 @@ function worker_start($process_name, $config)
*/ */
function get_realpath(string $file_path): string function get_realpath(string $file_path): string
{ {
if (strpos($file_path, 'phar://') === 0) { if (\strpos($file_path, 'phar://') === 0) {
return $file_path; return $file_path;
} else { } else {
return realpath($file_path); return \realpath($file_path);
} }
} }
...@@ -456,7 +458,7 @@ function get_realpath(string $file_path): string ...@@ -456,7 +458,7 @@ function get_realpath(string $file_path): string
*/ */
function is_phar() function is_phar()
{ {
return class_exists(\Phar::class, false) && Phar::running(); return \class_exists(\Phar::class, false) && Phar::running();
} }
/** /**
...@@ -469,26 +471,12 @@ function cpu_count() ...@@ -469,26 +471,12 @@ function cpu_count()
return 1; return 1;
} }
$count = 4; $count = 4;
if (is_callable('shell_exec')) { if (\is_callable('shell_exec')) {
if (strtolower(PHP_OS) === 'darwin') { if (\strtolower(PHP_OS) === 'darwin') {
$count = (int)shell_exec('sysctl -n machdep.cpu.core_count'); $count = (int)\shell_exec('sysctl -n machdep.cpu.core_count');
} else { } else {
$count = (int)shell_exec('nproc'); $count = (int)\shell_exec('nproc');
} }
} }
return $count > 0 ? $count : 4; return $count > 0 ? $count : 4;
} }
if (!function_exists('env')) {
/**
* Gets the value of an environment variable.
*
* @param string $key
* @param mixed $default
* @return mixed
*/
function env(string $key, $default = null)
{
return \Illuminate\Support\Env::get($key, $default);
}
}
\ No newline at end of file
...@@ -2,6 +2,11 @@ ...@@ -2,6 +2,11 @@
// autoload.php @generated by Composer // autoload.php @generated by Composer
if (PHP_VERSION_ID < 50600) {
echo 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
exit(1);
}
require_once __DIR__ . '/composer/autoload_real.php'; require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInit403af8cd99d7ed8c6ce0c15ef03b20d0::getLoader(); return ComposerAutoloaderInit403af8cd99d7ed8c6ce0c15ef03b20d0::getLoader();
...@@ -21,12 +21,14 @@ use Composer\Semver\VersionParser; ...@@ -21,12 +21,14 @@ use Composer\Semver\VersionParser;
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions * See also https://getcomposer.org/doc/07-runtime.md#installed-versions
* *
* To require its presence, you can require `composer-runtime-api ^2.0` * To require its presence, you can require `composer-runtime-api ^2.0`
*
* @final
*/ */
class InstalledVersions class InstalledVersions
{ {
/** /**
* @var mixed[]|null * @var mixed[]|null
* @psalm-var array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}|array{}|null * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
*/ */
private static $installed; private static $installed;
...@@ -37,7 +39,7 @@ class InstalledVersions ...@@ -37,7 +39,7 @@ class InstalledVersions
/** /**
* @var array[] * @var array[]
* @psalm-var array<string, array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}> * @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/ */
private static $installedByVendor = array(); private static $installedByVendor = array();
...@@ -241,7 +243,7 @@ class InstalledVersions ...@@ -241,7 +243,7 @@ class InstalledVersions
/** /**
* @return array * @return array
* @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string} * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
*/ */
public static function getRootPackage() public static function getRootPackage()
{ {
...@@ -255,7 +257,7 @@ class InstalledVersions ...@@ -255,7 +257,7 @@ class InstalledVersions
* *
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect. * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
* @return array[] * @return array[]
* @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>} * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
*/ */
public static function getRawData() public static function getRawData()
{ {
...@@ -278,7 +280,7 @@ class InstalledVersions ...@@ -278,7 +280,7 @@ class InstalledVersions
* Returns the raw data of all installed.php which are currently loaded for custom implementations * Returns the raw data of all installed.php which are currently loaded for custom implementations
* *
* @return array[] * @return array[]
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}> * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/ */
public static function getAllRawData() public static function getAllRawData()
{ {
...@@ -301,7 +303,7 @@ class InstalledVersions ...@@ -301,7 +303,7 @@ class InstalledVersions
* @param array[] $data A vendor/composer/installed.php data set * @param array[] $data A vendor/composer/installed.php data set
* @return void * @return void
* *
* @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>} $data * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
*/ */
public static function reload($data) public static function reload($data)
{ {
...@@ -311,7 +313,7 @@ class InstalledVersions ...@@ -311,7 +313,7 @@ class InstalledVersions
/** /**
* @return array[] * @return array[]
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}> * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/ */
private static function getInstalled() private static function getInstalled()
{ {
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// autoload_classmap.php @generated by Composer // autoload_classmap.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__)); $vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir); $baseDir = dirname($vendorDir);
return array( return array(
......
...@@ -2,26 +2,26 @@ ...@@ -2,26 +2,26 @@
// autoload_files.php @generated by Composer // autoload_files.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__)); $vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir); $baseDir = dirname($vendorDir);
return array( return array(
'6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php', '6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php',
'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php', 'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php',
'7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php', '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
'7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php',
'c964ee0ededf28c96ebd9db5099ef910' => $vendorDir . '/guzzlehttp/promises/src/functions_include.php', 'c964ee0ededf28c96ebd9db5099ef910' => $vendorDir . '/guzzlehttp/promises/src/functions_include.php',
'37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php', '37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php',
'9b552a3cc426e3287cc811caefa3cf53' => $vendorDir . '/topthink/think-helper/src/helper.php',
'320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php', '320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
'60799491728b879e74601d83e38b2cad' => $vendorDir . '/illuminate/collections/helpers.php', '9b552a3cc426e3287cc811caefa3cf53' => $vendorDir . '/topthink/think-helper/src/helper.php',
'8825ede83f2f289127722d4e842cf7e8' => $vendorDir . '/symfony/polyfill-intl-grapheme/bootstrap.php', '8825ede83f2f289127722d4e842cf7e8' => $vendorDir . '/symfony/polyfill-intl-grapheme/bootstrap.php',
'e69f7f6ee287b969198c3c9d6777bd38' => $vendorDir . '/symfony/polyfill-intl-normalizer/bootstrap.php', 'e69f7f6ee287b969198c3c9d6777bd38' => $vendorDir . '/symfony/polyfill-intl-normalizer/bootstrap.php',
'60799491728b879e74601d83e38b2cad' => $vendorDir . '/illuminate/collections/helpers.php',
'0d59ee240a4cd96ddbb4ff164fccea4d' => $vendorDir . '/symfony/polyfill-php73/bootstrap.php',
'b6b991a57620e2fb6b2f66f03fe9ddc2' => $vendorDir . '/symfony/string/Resources/functions.php',
'a1105708a18b76903365ca1c4aa61b02' => $vendorDir . '/symfony/translation/Resources/functions.php', 'a1105708a18b76903365ca1c4aa61b02' => $vendorDir . '/symfony/translation/Resources/functions.php',
'253c157292f75eb38082b5acb06f3f01' => $vendorDir . '/nikic/fast-route/src/functions.php', '253c157292f75eb38082b5acb06f3f01' => $vendorDir . '/nikic/fast-route/src/functions.php',
'538ca81a9a966a6716601ecf48f4eaef' => $vendorDir . '/opis/closure/functions.php', '538ca81a9a966a6716601ecf48f4eaef' => $vendorDir . '/opis/closure/functions.php',
'0d59ee240a4cd96ddbb4ff164fccea4d' => $vendorDir . '/symfony/polyfill-php73/bootstrap.php',
'b6b991a57620e2fb6b2f66f03fe9ddc2' => $vendorDir . '/symfony/string/Resources/functions.php',
'72579e7bd17821bb1321b87411366eae' => $vendorDir . '/illuminate/support/helpers.php', '72579e7bd17821bb1321b87411366eae' => $vendorDir . '/illuminate/support/helpers.php',
'2df68f9e79c919e2d88506611769ed2e' => $vendorDir . '/respect/stringifier/src/stringify.php', '2df68f9e79c919e2d88506611769ed2e' => $vendorDir . '/respect/stringifier/src/stringify.php',
'35fab96057f1bf5e7aba31a8a6d5fdde' => $vendorDir . '/topthink/think-orm/stubs/load_stubs.php', '35fab96057f1bf5e7aba31a8a6d5fdde' => $vendorDir . '/topthink/think-orm/stubs/load_stubs.php',
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// autoload_namespaces.php @generated by Composer // autoload_namespaces.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__)); $vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir); $baseDir = dirname($vendorDir);
return array( return array(
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// autoload_psr4.php @generated by Composer // autoload_psr4.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__)); $vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir); $baseDir = dirname($vendorDir);
return array( return array(
...@@ -12,6 +12,7 @@ return array( ...@@ -12,6 +12,7 @@ return array(
'Workerman\\' => array($vendorDir . '/workerman/workerman'), 'Workerman\\' => array($vendorDir . '/workerman/workerman'),
'Webman\\ThinkOrm\\' => array($vendorDir . '/webman/think-orm/src'), 'Webman\\ThinkOrm\\' => array($vendorDir . '/webman/think-orm/src'),
'Webman\\ThinkCache\\' => array($vendorDir . '/webman/think-cache/src'), 'Webman\\ThinkCache\\' => array($vendorDir . '/webman/think-cache/src'),
'Webman\\Console\\' => array($vendorDir . '/webman/console/src'),
'Webman\\AutoRoute\\' => array($vendorDir . '/webman/auto-route/src'), 'Webman\\AutoRoute\\' => array($vendorDir . '/webman/auto-route/src'),
'Webman\\ActionHook\\' => array($vendorDir . '/webman/action-hook/src'), 'Webman\\ActionHook\\' => array($vendorDir . '/webman/action-hook/src'),
'Webman\\' => array($vendorDir . '/workerman/webman-framework/src'), 'Webman\\' => array($vendorDir . '/workerman/webman-framework/src'),
......
...@@ -25,38 +25,15 @@ class ComposerAutoloaderInit403af8cd99d7ed8c6ce0c15ef03b20d0 ...@@ -25,38 +25,15 @@ class ComposerAutoloaderInit403af8cd99d7ed8c6ce0c15ef03b20d0
require __DIR__ . '/platform_check.php'; require __DIR__ . '/platform_check.php';
spl_autoload_register(array('ComposerAutoloaderInit403af8cd99d7ed8c6ce0c15ef03b20d0', 'loadClassLoader'), true, true); spl_autoload_register(array('ComposerAutoloaderInit403af8cd99d7ed8c6ce0c15ef03b20d0', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__))); self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
spl_autoload_unregister(array('ComposerAutoloaderInit403af8cd99d7ed8c6ce0c15ef03b20d0', 'loadClassLoader')); spl_autoload_unregister(array('ComposerAutoloaderInit403af8cd99d7ed8c6ce0c15ef03b20d0', 'loadClassLoader'));
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); require __DIR__ . '/autoload_static.php';
if ($useStaticLoader) { call_user_func(\Composer\Autoload\ComposerStaticInit403af8cd99d7ed8c6ce0c15ef03b20d0::getInitializer($loader));
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInit403af8cd99d7ed8c6ce0c15ef03b20d0::getInitializer($loader));
} else {
$map = require __DIR__ . '/autoload_namespaces.php';
foreach ($map as $namespace => $path) {
$loader->set($namespace, $path);
}
$map = require __DIR__ . '/autoload_psr4.php';
foreach ($map as $namespace => $path) {
$loader->setPsr4($namespace, $path);
}
$classMap = require __DIR__ . '/autoload_classmap.php';
if ($classMap) {
$loader->addClassMap($classMap);
}
}
$loader->register(true); $loader->register(true);
if ($useStaticLoader) { $includeFiles = \Composer\Autoload\ComposerStaticInit403af8cd99d7ed8c6ce0c15ef03b20d0::$files;
$includeFiles = Composer\Autoload\ComposerStaticInit403af8cd99d7ed8c6ce0c15ef03b20d0::$files;
} else {
$includeFiles = require __DIR__ . '/autoload_files.php';
}
foreach ($includeFiles as $fileIdentifier => $file) { foreach ($includeFiles as $fileIdentifier => $file) {
composerRequire403af8cd99d7ed8c6ce0c15ef03b20d0($fileIdentifier, $file); composerRequire403af8cd99d7ed8c6ce0c15ef03b20d0($fileIdentifier, $file);
} }
......
...@@ -9,20 +9,20 @@ class ComposerStaticInit403af8cd99d7ed8c6ce0c15ef03b20d0 ...@@ -9,20 +9,20 @@ class ComposerStaticInit403af8cd99d7ed8c6ce0c15ef03b20d0
public static $files = array ( public static $files = array (
'6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php', '6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php',
'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php', 'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
'7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php', '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
'7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php',
'c964ee0ededf28c96ebd9db5099ef910' => __DIR__ . '/..' . '/guzzlehttp/promises/src/functions_include.php', 'c964ee0ededf28c96ebd9db5099ef910' => __DIR__ . '/..' . '/guzzlehttp/promises/src/functions_include.php',
'37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php', '37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php',
'9b552a3cc426e3287cc811caefa3cf53' => __DIR__ . '/..' . '/topthink/think-helper/src/helper.php',
'320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php', '320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
'60799491728b879e74601d83e38b2cad' => __DIR__ . '/..' . '/illuminate/collections/helpers.php', '9b552a3cc426e3287cc811caefa3cf53' => __DIR__ . '/..' . '/topthink/think-helper/src/helper.php',
'8825ede83f2f289127722d4e842cf7e8' => __DIR__ . '/..' . '/symfony/polyfill-intl-grapheme/bootstrap.php', '8825ede83f2f289127722d4e842cf7e8' => __DIR__ . '/..' . '/symfony/polyfill-intl-grapheme/bootstrap.php',
'e69f7f6ee287b969198c3c9d6777bd38' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/bootstrap.php', 'e69f7f6ee287b969198c3c9d6777bd38' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/bootstrap.php',
'60799491728b879e74601d83e38b2cad' => __DIR__ . '/..' . '/illuminate/collections/helpers.php',
'0d59ee240a4cd96ddbb4ff164fccea4d' => __DIR__ . '/..' . '/symfony/polyfill-php73/bootstrap.php',
'b6b991a57620e2fb6b2f66f03fe9ddc2' => __DIR__ . '/..' . '/symfony/string/Resources/functions.php',
'a1105708a18b76903365ca1c4aa61b02' => __DIR__ . '/..' . '/symfony/translation/Resources/functions.php', 'a1105708a18b76903365ca1c4aa61b02' => __DIR__ . '/..' . '/symfony/translation/Resources/functions.php',
'253c157292f75eb38082b5acb06f3f01' => __DIR__ . '/..' . '/nikic/fast-route/src/functions.php', '253c157292f75eb38082b5acb06f3f01' => __DIR__ . '/..' . '/nikic/fast-route/src/functions.php',
'538ca81a9a966a6716601ecf48f4eaef' => __DIR__ . '/..' . '/opis/closure/functions.php', '538ca81a9a966a6716601ecf48f4eaef' => __DIR__ . '/..' . '/opis/closure/functions.php',
'0d59ee240a4cd96ddbb4ff164fccea4d' => __DIR__ . '/..' . '/symfony/polyfill-php73/bootstrap.php',
'b6b991a57620e2fb6b2f66f03fe9ddc2' => __DIR__ . '/..' . '/symfony/string/Resources/functions.php',
'72579e7bd17821bb1321b87411366eae' => __DIR__ . '/..' . '/illuminate/support/helpers.php', '72579e7bd17821bb1321b87411366eae' => __DIR__ . '/..' . '/illuminate/support/helpers.php',
'2df68f9e79c919e2d88506611769ed2e' => __DIR__ . '/..' . '/respect/stringifier/src/stringify.php', '2df68f9e79c919e2d88506611769ed2e' => __DIR__ . '/..' . '/respect/stringifier/src/stringify.php',
'35fab96057f1bf5e7aba31a8a6d5fdde' => __DIR__ . '/..' . '/topthink/think-orm/stubs/load_stubs.php', '35fab96057f1bf5e7aba31a8a6d5fdde' => __DIR__ . '/..' . '/topthink/think-orm/stubs/load_stubs.php',
...@@ -48,6 +48,7 @@ class ComposerStaticInit403af8cd99d7ed8c6ce0c15ef03b20d0 ...@@ -48,6 +48,7 @@ class ComposerStaticInit403af8cd99d7ed8c6ce0c15ef03b20d0
'Workerman\\' => 10, 'Workerman\\' => 10,
'Webman\\ThinkOrm\\' => 16, 'Webman\\ThinkOrm\\' => 16,
'Webman\\ThinkCache\\' => 18, 'Webman\\ThinkCache\\' => 18,
'Webman\\Console\\' => 15,
'Webman\\AutoRoute\\' => 17, 'Webman\\AutoRoute\\' => 17,
'Webman\\ActionHook\\' => 18, 'Webman\\ActionHook\\' => 18,
'Webman\\' => 7, 'Webman\\' => 7,
...@@ -165,6 +166,10 @@ class ComposerStaticInit403af8cd99d7ed8c6ce0c15ef03b20d0 ...@@ -165,6 +166,10 @@ class ComposerStaticInit403af8cd99d7ed8c6ce0c15ef03b20d0
array ( array (
0 => __DIR__ . '/..' . '/webman/think-cache/src', 0 => __DIR__ . '/..' . '/webman/think-cache/src',
), ),
'Webman\\Console\\' =>
array (
0 => __DIR__ . '/..' . '/webman/console/src',
),
'Webman\\AutoRoute\\' => 'Webman\\AutoRoute\\' =>
array ( array (
0 => __DIR__ . '/..' . '/webman/auto-route/src', 0 => __DIR__ . '/..' . '/webman/auto-route/src',
......
...@@ -3790,6 +3790,61 @@ ...@@ -3790,6 +3790,61 @@
}, },
"install-path": "../webman/auto-route" "install-path": "../webman/auto-route"
}, },
{
"name": "webman/console",
"version": "v1.0.27",
"version_normalized": "1.0.27.0",
"source": {
"type": "git",
"url": "https://github.com/webman-php/console.git",
"reference": "e450967eaabc43eb0c93cfcd6d8f420c16e22b67"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/webman-php/console/zipball/e450967eaabc43eb0c93cfcd6d8f420c16e22b67",
"reference": "e450967eaabc43eb0c93cfcd6d8f420c16e22b67",
"shasum": ""
},
"require": {
"symfony/console": ">=5.0"
},
"require-dev": {
"workerman/webman": "^1.0"
},
"time": "2022-07-01T08:59:02+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"Webman\\Console\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "walkor",
"email": "walkor@workerman.net",
"homepage": "http://www.workerman.net",
"role": "Developer"
}
],
"description": "Webman console",
"homepage": "http://www.workerman.net",
"keywords": [
"webman console"
],
"support": {
"email": "walkor@workerman.net",
"forum": "http://www.workerman.net/questions",
"issues": "https://github.com/webman-php/console/issues",
"source": "https://github.com/webman-php/console",
"wiki": "http://www.workerman.net/doc/webman"
},
"install-path": "../webman/console"
},
{ {
"name": "webman/think-cache", "name": "webman/think-cache",
"version": "v1.0.1", "version": "v1.0.1",
...@@ -3936,17 +3991,17 @@ ...@@ -3936,17 +3991,17 @@
}, },
{ {
"name": "workerman/webman-framework", "name": "workerman/webman-framework",
"version": "v1.3.12", "version": "v1.4.3",
"version_normalized": "1.3.12.0", "version_normalized": "1.4.3.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/walkor/webman-framework.git", "url": "https://github.com/walkor/webman-framework.git",
"reference": "a5b392e68a88993e2c94f73805630458b6058c01" "reference": "0f4d5b6c58823656bdc9603f762d4be6e41ae380"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/walkor/webman-framework/zipball/a5b392e68a88993e2c94f73805630458b6058c01", "url": "https://api.github.com/repos/walkor/webman-framework/zipball/0f4d5b6c58823656bdc9603f762d4be6e41ae380",
"reference": "a5b392e68a88993e2c94f73805630458b6058c01", "reference": "0f4d5b6c58823656bdc9603f762d4be6e41ae380",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
...@@ -3958,7 +4013,7 @@ ...@@ -3958,7 +4013,7 @@
"suggest": { "suggest": {
"ext-event": "For better performance. " "ext-event": "For better performance. "
}, },
"time": "2022-04-28T12:25:46+00:00", "time": "2022-08-15T12:35:14+00:00",
"type": "library", "type": "library",
"installation-source": "dist", "installation-source": "dist",
"autoload": { "autoload": {
......
<?php return array( <?php return array(
'root' => array( 'root' => array(
'pretty_version' => 'dev-master', 'name' => 'workerman/webman',
'version' => 'dev-master', 'pretty_version' => '1.0.0+no-version-set',
'version' => '1.0.0.0',
'reference' => NULL,
'type' => 'project', 'type' => 'project',
'install_path' => __DIR__ . '/../../', 'install_path' => __DIR__ . '/../../',
'aliases' => array(), 'aliases' => array(),
'reference' => '8328e092da79093ae4d0d8e87589ad419cedf7a8',
'name' => 'workerman/webman',
'dev' => true, 'dev' => true,
), ),
'versions' => array( 'versions' => array(
'aliyuncs/oss-sdk-php' => array( 'aliyuncs/oss-sdk-php' => array(
'pretty_version' => 'v2.4.3', 'pretty_version' => 'v2.4.3',
'version' => '2.4.3.0', 'version' => '2.4.3.0',
'reference' => '4ccead614915ee6685bf30016afb01aabd347e46',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../aliyuncs/oss-sdk-php', 'install_path' => __DIR__ . '/../aliyuncs/oss-sdk-php',
'aliases' => array(), 'aliases' => array(),
'reference' => '4ccead614915ee6685bf30016afb01aabd347e46',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'doctrine/inflector' => array( 'doctrine/inflector' => array(
'pretty_version' => '2.0.4', 'pretty_version' => '2.0.4',
'version' => '2.0.4.0', 'version' => '2.0.4.0',
'reference' => '8b7ff3e4b7de6b2c84da85637b59fd2880ecaa89',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../doctrine/inflector', 'install_path' => __DIR__ . '/../doctrine/inflector',
'aliases' => array(), 'aliases' => array(),
'reference' => '8b7ff3e4b7de6b2c84da85637b59fd2880ecaa89',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'graham-campbell/result-type' => array( 'graham-campbell/result-type' => array(
'pretty_version' => 'v1.0.4', 'pretty_version' => 'v1.0.4',
'version' => '1.0.4.0', 'version' => '1.0.4.0',
'reference' => '0690bde05318336c7221785f2a932467f98b64ca',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../graham-campbell/result-type', 'install_path' => __DIR__ . '/../graham-campbell/result-type',
'aliases' => array(), 'aliases' => array(),
'reference' => '0690bde05318336c7221785f2a932467f98b64ca',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'gregwar/captcha' => array( 'gregwar/captcha' => array(
'pretty_version' => 'v1.1.9', 'pretty_version' => 'v1.1.9',
'version' => '1.1.9.0', 'version' => '1.1.9.0',
'reference' => '4bb668e6b40e3205a020ca5ee4ca8cff8b8780c5',
'type' => 'captcha', 'type' => 'captcha',
'install_path' => __DIR__ . '/../gregwar/captcha', 'install_path' => __DIR__ . '/../gregwar/captcha',
'aliases' => array(), 'aliases' => array(),
'reference' => '4bb668e6b40e3205a020ca5ee4ca8cff8b8780c5',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'guzzlehttp/command' => array( 'guzzlehttp/command' => array(
'pretty_version' => '1.2.2', 'pretty_version' => '1.2.2',
'version' => '1.2.2.0', 'version' => '1.2.2.0',
'reference' => '7883359e0ecab8a8f7c43aad2fc36360a35d21e8',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/command', 'install_path' => __DIR__ . '/../guzzlehttp/command',
'aliases' => array(), 'aliases' => array(),
'reference' => '7883359e0ecab8a8f7c43aad2fc36360a35d21e8',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'guzzlehttp/guzzle' => array( 'guzzlehttp/guzzle' => array(
'pretty_version' => '7.4.2', 'pretty_version' => '7.4.2',
'version' => '7.4.2.0', 'version' => '7.4.2.0',
'reference' => 'ac1ec1cd9b5624694c3a40be801d94137afb12b4',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/guzzle', 'install_path' => __DIR__ . '/../guzzlehttp/guzzle',
'aliases' => array(), 'aliases' => array(),
'reference' => 'ac1ec1cd9b5624694c3a40be801d94137afb12b4',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'guzzlehttp/guzzle-services' => array( 'guzzlehttp/guzzle-services' => array(
'pretty_version' => '1.3.2', 'pretty_version' => '1.3.2',
'version' => '1.3.2.0', 'version' => '1.3.2.0',
'reference' => '4989d902dd4e0411b320e851c46f3c94d652d891',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/guzzle-services', 'install_path' => __DIR__ . '/../guzzlehttp/guzzle-services',
'aliases' => array(), 'aliases' => array(),
'reference' => '4989d902dd4e0411b320e851c46f3c94d652d891',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'guzzlehttp/promises' => array( 'guzzlehttp/promises' => array(
'pretty_version' => '1.5.1', 'pretty_version' => '1.5.1',
'version' => '1.5.1.0', 'version' => '1.5.1.0',
'reference' => 'fe752aedc9fd8fcca3fe7ad05d419d32998a06da',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/promises', 'install_path' => __DIR__ . '/../guzzlehttp/promises',
'aliases' => array(), 'aliases' => array(),
'reference' => 'fe752aedc9fd8fcca3fe7ad05d419d32998a06da',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'guzzlehttp/psr7' => array( 'guzzlehttp/psr7' => array(
'pretty_version' => '2.2.1', 'pretty_version' => '2.2.1',
'version' => '2.2.1.0', 'version' => '2.2.1.0',
'reference' => 'c94a94f120803a18554c1805ef2e539f8285f9a2',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/psr7', 'install_path' => __DIR__ . '/../guzzlehttp/psr7',
'aliases' => array(), 'aliases' => array(),
'reference' => 'c94a94f120803a18554c1805ef2e539f8285f9a2',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'guzzlehttp/uri-template' => array( 'guzzlehttp/uri-template' => array(
'pretty_version' => 'v1.0.1', 'pretty_version' => 'v1.0.1',
'version' => '1.0.1.0', 'version' => '1.0.1.0',
'reference' => 'b945d74a55a25a949158444f09ec0d3c120d69e2',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/uri-template', 'install_path' => __DIR__ . '/../guzzlehttp/uri-template',
'aliases' => array(), 'aliases' => array(),
'reference' => 'b945d74a55a25a949158444f09ec0d3c120d69e2',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'illuminate/collections' => array( 'illuminate/collections' => array(
'pretty_version' => 'v8.83.10', 'pretty_version' => 'v8.83.10',
'version' => '8.83.10.0', 'version' => '8.83.10.0',
'reference' => 'fc232e89c0214dba5d2b431220a24b02d480a472',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../illuminate/collections', 'install_path' => __DIR__ . '/../illuminate/collections',
'aliases' => array(), 'aliases' => array(),
'reference' => 'fc232e89c0214dba5d2b431220a24b02d480a472',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'illuminate/container' => array( 'illuminate/container' => array(
'pretty_version' => 'v8.83.10', 'pretty_version' => 'v8.83.10',
'version' => '8.83.10.0', 'version' => '8.83.10.0',
'reference' => '14062628d05f75047c5a1360b9350028427d568e',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../illuminate/container', 'install_path' => __DIR__ . '/../illuminate/container',
'aliases' => array(), 'aliases' => array(),
'reference' => '14062628d05f75047c5a1360b9350028427d568e',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'illuminate/contracts' => array( 'illuminate/contracts' => array(
'pretty_version' => 'v8.83.10', 'pretty_version' => 'v8.83.10',
'version' => '8.83.10.0', 'version' => '8.83.10.0',
'reference' => '5e0fd287a1b22a6b346a9f7cd484d8cf0234585d',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../illuminate/contracts', 'install_path' => __DIR__ . '/../illuminate/contracts',
'aliases' => array(), 'aliases' => array(),
'reference' => '5e0fd287a1b22a6b346a9f7cd484d8cf0234585d',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'illuminate/database' => array( 'illuminate/database' => array(
'pretty_version' => 'v8.83.10', 'pretty_version' => 'v8.83.10',
'version' => '8.83.10.0', 'version' => '8.83.10.0',
'reference' => '5a09b780d86613127cddbeb05e4dde22aeccbedf',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../illuminate/database', 'install_path' => __DIR__ . '/../illuminate/database',
'aliases' => array(), 'aliases' => array(),
'reference' => '5a09b780d86613127cddbeb05e4dde22aeccbedf',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'illuminate/macroable' => array( 'illuminate/macroable' => array(
'pretty_version' => 'v8.83.10', 'pretty_version' => 'v8.83.10',
'version' => '8.83.10.0', 'version' => '8.83.10.0',
'reference' => 'aed81891a6e046fdee72edd497f822190f61c162',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../illuminate/macroable', 'install_path' => __DIR__ . '/../illuminate/macroable',
'aliases' => array(), 'aliases' => array(),
'reference' => 'aed81891a6e046fdee72edd497f822190f61c162',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'illuminate/support' => array( 'illuminate/support' => array(
'pretty_version' => 'v8.83.10', 'pretty_version' => 'v8.83.10',
'version' => '8.83.10.0', 'version' => '8.83.10.0',
'reference' => '3f1de19528fc235d666f73d540d13a684da6bf3a',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../illuminate/support', 'install_path' => __DIR__ . '/../illuminate/support',
'aliases' => array(), 'aliases' => array(),
'reference' => '3f1de19528fc235d666f73d540d13a684da6bf3a',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'jasongrimes/paginator' => array( 'jasongrimes/paginator' => array(
'pretty_version' => '1.0.3', 'pretty_version' => '1.0.3',
'version' => '1.0.3.0', 'version' => '1.0.3.0',
'reference' => '3411e3cd0c6479a0b514f26e4358f0273552f221',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../jasongrimes/paginator', 'install_path' => __DIR__ . '/../jasongrimes/paginator',
'aliases' => array(), 'aliases' => array(),
'reference' => '3411e3cd0c6479a0b514f26e4358f0273552f221',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'monolog/monolog' => array( 'monolog/monolog' => array(
'pretty_version' => '2.5.0', 'pretty_version' => '2.5.0',
'version' => '2.5.0.0', 'version' => '2.5.0.0',
'reference' => '4192345e260f1d51b365536199744b987e160edc',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../monolog/monolog', 'install_path' => __DIR__ . '/../monolog/monolog',
'aliases' => array(), 'aliases' => array(),
'reference' => '4192345e260f1d51b365536199744b987e160edc',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'nesbot/carbon' => array( 'nesbot/carbon' => array(
'pretty_version' => '2.57.0', 'pretty_version' => '2.57.0',
'version' => '2.57.0.0', 'version' => '2.57.0.0',
'reference' => '4a54375c21eea4811dbd1149fe6b246517554e78',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../nesbot/carbon', 'install_path' => __DIR__ . '/../nesbot/carbon',
'aliases' => array(), 'aliases' => array(),
'reference' => '4a54375c21eea4811dbd1149fe6b246517554e78',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'nikic/fast-route' => array( 'nikic/fast-route' => array(
'pretty_version' => 'v1.3.0', 'pretty_version' => 'v1.3.0',
'version' => '1.3.0.0', 'version' => '1.3.0.0',
'reference' => '181d480e08d9476e61381e04a71b34dc0432e812',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../nikic/fast-route', 'install_path' => __DIR__ . '/../nikic/fast-route',
'aliases' => array(), 'aliases' => array(),
'reference' => '181d480e08d9476e61381e04a71b34dc0432e812',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'opis/closure' => array( 'opis/closure' => array(
'pretty_version' => '3.6.3', 'pretty_version' => '3.6.3',
'version' => '3.6.3.0', 'version' => '3.6.3.0',
'reference' => '3d81e4309d2a927abbe66df935f4bb60082805ad',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../opis/closure', 'install_path' => __DIR__ . '/../opis/closure',
'aliases' => array(), 'aliases' => array(),
'reference' => '3d81e4309d2a927abbe66df935f4bb60082805ad',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'phpoption/phpoption' => array( 'phpoption/phpoption' => array(
'pretty_version' => '1.8.1', 'pretty_version' => '1.8.1',
'version' => '1.8.1.0', 'version' => '1.8.1.0',
'reference' => 'eab7a0df01fe2344d172bff4cd6dbd3f8b84ad15',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../phpoption/phpoption', 'install_path' => __DIR__ . '/../phpoption/phpoption',
'aliases' => array(), 'aliases' => array(),
'reference' => 'eab7a0df01fe2344d172bff4cd6dbd3f8b84ad15',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'psr/cache' => array( 'psr/cache' => array(
'pretty_version' => '1.0.1', 'pretty_version' => '1.0.1',
'version' => '1.0.1.0', 'version' => '1.0.1.0',
'reference' => 'd11b50ad223250cf17b86e38383413f5a6764bf8',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../psr/cache', 'install_path' => __DIR__ . '/../psr/cache',
'aliases' => array(), 'aliases' => array(),
'reference' => 'd11b50ad223250cf17b86e38383413f5a6764bf8',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'psr/container' => array( 'psr/container' => array(
'pretty_version' => '1.1.2', 'pretty_version' => '1.1.2',
'version' => '1.1.2.0', 'version' => '1.1.2.0',
'reference' => '513e0666f7216c7459170d56df27dfcefe1689ea',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../psr/container', 'install_path' => __DIR__ . '/../psr/container',
'aliases' => array(), 'aliases' => array(),
'reference' => '513e0666f7216c7459170d56df27dfcefe1689ea',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'psr/container-implementation' => array( 'psr/container-implementation' => array(
...@@ -235,10 +235,10 @@ ...@@ -235,10 +235,10 @@
'psr/http-client' => array( 'psr/http-client' => array(
'pretty_version' => '1.0.1', 'pretty_version' => '1.0.1',
'version' => '1.0.1.0', 'version' => '1.0.1.0',
'reference' => '2dfb5f6c5eff0e91e20e913f8c5452ed95b86621',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../psr/http-client', 'install_path' => __DIR__ . '/../psr/http-client',
'aliases' => array(), 'aliases' => array(),
'reference' => '2dfb5f6c5eff0e91e20e913f8c5452ed95b86621',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'psr/http-client-implementation' => array( 'psr/http-client-implementation' => array(
...@@ -250,10 +250,10 @@ ...@@ -250,10 +250,10 @@
'psr/http-factory' => array( 'psr/http-factory' => array(
'pretty_version' => '1.0.1', 'pretty_version' => '1.0.1',
'version' => '1.0.1.0', 'version' => '1.0.1.0',
'reference' => '12ac7fcd07e5b077433f5f2bee95b3a771bf61be',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../psr/http-factory', 'install_path' => __DIR__ . '/../psr/http-factory',
'aliases' => array(), 'aliases' => array(),
'reference' => '12ac7fcd07e5b077433f5f2bee95b3a771bf61be',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'psr/http-factory-implementation' => array( 'psr/http-factory-implementation' => array(
...@@ -265,10 +265,10 @@ ...@@ -265,10 +265,10 @@
'psr/http-message' => array( 'psr/http-message' => array(
'pretty_version' => '1.0.1', 'pretty_version' => '1.0.1',
'version' => '1.0.1.0', 'version' => '1.0.1.0',
'reference' => 'f6561bf28d520154e4b0ec72be95418abe6d9363',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../psr/http-message', 'install_path' => __DIR__ . '/../psr/http-message',
'aliases' => array(), 'aliases' => array(),
'reference' => 'f6561bf28d520154e4b0ec72be95418abe6d9363',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'psr/http-message-implementation' => array( 'psr/http-message-implementation' => array(
...@@ -280,10 +280,10 @@ ...@@ -280,10 +280,10 @@
'psr/log' => array( 'psr/log' => array(
'pretty_version' => '1.1.4', 'pretty_version' => '1.1.4',
'version' => '1.1.4.0', 'version' => '1.1.4.0',
'reference' => 'd49695b909c3b7628b6289db5479a1c204601f11',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../psr/log', 'install_path' => __DIR__ . '/../psr/log',
'aliases' => array(), 'aliases' => array(),
'reference' => 'd49695b909c3b7628b6289db5479a1c204601f11',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'psr/log-implementation' => array( 'psr/log-implementation' => array(
...@@ -296,154 +296,154 @@ ...@@ -296,154 +296,154 @@
'psr/simple-cache' => array( 'psr/simple-cache' => array(
'pretty_version' => '1.0.1', 'pretty_version' => '1.0.1',
'version' => '1.0.1.0', 'version' => '1.0.1.0',
'reference' => '408d5eafb83c57f6365a3ca330ff23aa4a5fa39b',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../psr/simple-cache', 'install_path' => __DIR__ . '/../psr/simple-cache',
'aliases' => array(), 'aliases' => array(),
'reference' => '408d5eafb83c57f6365a3ca330ff23aa4a5fa39b',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'qcloud/cos-sdk-v5' => array( 'qcloud/cos-sdk-v5' => array(
'pretty_version' => 'v2.5.5', 'pretty_version' => 'v2.5.5',
'version' => '2.5.5.0', 'version' => '2.5.5.0',
'reference' => '40e51efc05d5addeb9029db7840846809bd666c4',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../qcloud/cos-sdk-v5', 'install_path' => __DIR__ . '/../qcloud/cos-sdk-v5',
'aliases' => array(), 'aliases' => array(),
'reference' => '40e51efc05d5addeb9029db7840846809bd666c4',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'ralouphie/getallheaders' => array( 'ralouphie/getallheaders' => array(
'pretty_version' => '3.0.3', 'pretty_version' => '3.0.3',
'version' => '3.0.3.0', 'version' => '3.0.3.0',
'reference' => '120b605dfeb996808c31b6477290a714d356e822',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../ralouphie/getallheaders', 'install_path' => __DIR__ . '/../ralouphie/getallheaders',
'aliases' => array(), 'aliases' => array(),
'reference' => '120b605dfeb996808c31b6477290a714d356e822',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'respect/stringifier' => array( 'respect/stringifier' => array(
'pretty_version' => '0.2.0', 'pretty_version' => '0.2.0',
'version' => '0.2.0.0', 'version' => '0.2.0.0',
'reference' => 'e55af3c8aeaeaa2abb5fa47a58a8e9688cc23b59',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../respect/stringifier', 'install_path' => __DIR__ . '/../respect/stringifier',
'aliases' => array(), 'aliases' => array(),
'reference' => 'e55af3c8aeaeaa2abb5fa47a58a8e9688cc23b59',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'symfony/console' => array( 'symfony/console' => array(
'pretty_version' => 'v5.4.8', 'pretty_version' => 'v5.4.8',
'version' => '5.4.8.0', 'version' => '5.4.8.0',
'reference' => 'ffe3aed36c4d60da2cf1b0a1cee6b8f2e5fa881b',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../symfony/console', 'install_path' => __DIR__ . '/../symfony/console',
'aliases' => array(), 'aliases' => array(),
'reference' => 'ffe3aed36c4d60da2cf1b0a1cee6b8f2e5fa881b',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'symfony/deprecation-contracts' => array( 'symfony/deprecation-contracts' => array(
'pretty_version' => 'v2.5.1', 'pretty_version' => 'v2.5.1',
'version' => '2.5.1.0', 'version' => '2.5.1.0',
'reference' => 'e8b495ea28c1d97b5e0c121748d6f9b53d075c66',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../symfony/deprecation-contracts', 'install_path' => __DIR__ . '/../symfony/deprecation-contracts',
'aliases' => array(), 'aliases' => array(),
'reference' => 'e8b495ea28c1d97b5e0c121748d6f9b53d075c66',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'symfony/finder' => array( 'symfony/finder' => array(
'pretty_version' => 'v5.4.8', 'pretty_version' => 'v5.4.8',
'version' => '5.4.8.0', 'version' => '5.4.8.0',
'reference' => '9b630f3427f3ebe7cd346c277a1408b00249dad9',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../symfony/finder', 'install_path' => __DIR__ . '/../symfony/finder',
'aliases' => array(), 'aliases' => array(),
'reference' => '9b630f3427f3ebe7cd346c277a1408b00249dad9',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'symfony/polyfill-ctype' => array( 'symfony/polyfill-ctype' => array(
'pretty_version' => 'v1.25.0', 'pretty_version' => 'v1.25.0',
'version' => '1.25.0.0', 'version' => '1.25.0.0',
'reference' => '30885182c981ab175d4d034db0f6f469898070ab',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-ctype', 'install_path' => __DIR__ . '/../symfony/polyfill-ctype',
'aliases' => array(), 'aliases' => array(),
'reference' => '30885182c981ab175d4d034db0f6f469898070ab',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'symfony/polyfill-intl-grapheme' => array( 'symfony/polyfill-intl-grapheme' => array(
'pretty_version' => 'v1.25.0', 'pretty_version' => 'v1.25.0',
'version' => '1.25.0.0', 'version' => '1.25.0.0',
'reference' => '81b86b50cf841a64252b439e738e97f4a34e2783',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-intl-grapheme', 'install_path' => __DIR__ . '/../symfony/polyfill-intl-grapheme',
'aliases' => array(), 'aliases' => array(),
'reference' => '81b86b50cf841a64252b439e738e97f4a34e2783',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'symfony/polyfill-intl-normalizer' => array( 'symfony/polyfill-intl-normalizer' => array(
'pretty_version' => 'v1.25.0', 'pretty_version' => 'v1.25.0',
'version' => '1.25.0.0', 'version' => '1.25.0.0',
'reference' => '8590a5f561694770bdcd3f9b5c69dde6945028e8',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-intl-normalizer', 'install_path' => __DIR__ . '/../symfony/polyfill-intl-normalizer',
'aliases' => array(), 'aliases' => array(),
'reference' => '8590a5f561694770bdcd3f9b5c69dde6945028e8',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'symfony/polyfill-mbstring' => array( 'symfony/polyfill-mbstring' => array(
'pretty_version' => 'v1.25.0', 'pretty_version' => 'v1.25.0',
'version' => '1.25.0.0', 'version' => '1.25.0.0',
'reference' => '0abb51d2f102e00a4eefcf46ba7fec406d245825',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-mbstring', 'install_path' => __DIR__ . '/../symfony/polyfill-mbstring',
'aliases' => array(), 'aliases' => array(),
'reference' => '0abb51d2f102e00a4eefcf46ba7fec406d245825',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'symfony/polyfill-php73' => array( 'symfony/polyfill-php73' => array(
'pretty_version' => 'v1.25.0', 'pretty_version' => 'v1.25.0',
'version' => '1.25.0.0', 'version' => '1.25.0.0',
'reference' => 'cc5db0e22b3cb4111010e48785a97f670b350ca5',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-php73', 'install_path' => __DIR__ . '/../symfony/polyfill-php73',
'aliases' => array(), 'aliases' => array(),
'reference' => 'cc5db0e22b3cb4111010e48785a97f670b350ca5',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'symfony/polyfill-php80' => array( 'symfony/polyfill-php80' => array(
'pretty_version' => 'v1.25.0', 'pretty_version' => 'v1.25.0',
'version' => '1.25.0.0', 'version' => '1.25.0.0',
'reference' => '4407588e0d3f1f52efb65fbe92babe41f37fe50c',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-php80', 'install_path' => __DIR__ . '/../symfony/polyfill-php80',
'aliases' => array(), 'aliases' => array(),
'reference' => '4407588e0d3f1f52efb65fbe92babe41f37fe50c',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'symfony/service-contracts' => array( 'symfony/service-contracts' => array(
'pretty_version' => 'v2.5.1', 'pretty_version' => 'v2.5.1',
'version' => '2.5.1.0', 'version' => '2.5.1.0',
'reference' => '24d9dc654b83e91aa59f9d167b131bc3b5bea24c',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../symfony/service-contracts', 'install_path' => __DIR__ . '/../symfony/service-contracts',
'aliases' => array(), 'aliases' => array(),
'reference' => '24d9dc654b83e91aa59f9d167b131bc3b5bea24c',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'symfony/string' => array( 'symfony/string' => array(
'pretty_version' => 'v5.4.8', 'pretty_version' => 'v5.4.8',
'version' => '5.4.8.0', 'version' => '5.4.8.0',
'reference' => '3c061a76bff6d6ea427d85e12ad1bb8ed8cd43e8',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../symfony/string', 'install_path' => __DIR__ . '/../symfony/string',
'aliases' => array(), 'aliases' => array(),
'reference' => '3c061a76bff6d6ea427d85e12ad1bb8ed8cd43e8',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'symfony/translation' => array( 'symfony/translation' => array(
'pretty_version' => 'v5.4.8', 'pretty_version' => 'v5.4.8',
'version' => '5.4.8.0', 'version' => '5.4.8.0',
'reference' => 'f5c0f6d1f20993b2606f3a5f36b1dc8c1899170b',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../symfony/translation', 'install_path' => __DIR__ . '/../symfony/translation',
'aliases' => array(), 'aliases' => array(),
'reference' => 'f5c0f6d1f20993b2606f3a5f36b1dc8c1899170b',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'symfony/translation-contracts' => array( 'symfony/translation-contracts' => array(
'pretty_version' => 'v2.5.1', 'pretty_version' => 'v2.5.1',
'version' => '2.5.1.0', 'version' => '2.5.1.0',
'reference' => '1211df0afa701e45a04253110e959d4af4ef0f07',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../symfony/translation-contracts', 'install_path' => __DIR__ . '/../symfony/translation-contracts',
'aliases' => array(), 'aliases' => array(),
'reference' => '1211df0afa701e45a04253110e959d4af4ef0f07',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'symfony/translation-implementation' => array( 'symfony/translation-implementation' => array(
...@@ -455,136 +455,145 @@ ...@@ -455,136 +455,145 @@
'topthink/think-cache' => array( 'topthink/think-cache' => array(
'pretty_version' => 'v2.0.6', 'pretty_version' => 'v2.0.6',
'version' => '2.0.6.0', 'version' => '2.0.6.0',
'reference' => '75a56b24affc65b51688fd89ada48c102757fd74',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../topthink/think-cache', 'install_path' => __DIR__ . '/../topthink/think-cache',
'aliases' => array(), 'aliases' => array(),
'reference' => '75a56b24affc65b51688fd89ada48c102757fd74',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'topthink/think-container' => array( 'topthink/think-container' => array(
'pretty_version' => 'v2.0.4', 'pretty_version' => 'v2.0.4',
'version' => '2.0.4.0', 'version' => '2.0.4.0',
'reference' => '15c6d5813367c7c0cf501c7c043f48a6f359375c',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../topthink/think-container', 'install_path' => __DIR__ . '/../topthink/think-container',
'aliases' => array(), 'aliases' => array(),
'reference' => '15c6d5813367c7c0cf501c7c043f48a6f359375c',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'topthink/think-helper' => array( 'topthink/think-helper' => array(
'pretty_version' => 'v3.1.6', 'pretty_version' => 'v3.1.6',
'version' => '3.1.6.0', 'version' => '3.1.6.0',
'reference' => '769acbe50a4274327162f9c68ec2e89a38eb2aff',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../topthink/think-helper', 'install_path' => __DIR__ . '/../topthink/think-helper',
'aliases' => array(), 'aliases' => array(),
'reference' => '769acbe50a4274327162f9c68ec2e89a38eb2aff',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'topthink/think-orm' => array( 'topthink/think-orm' => array(
'pretty_version' => 'v2.0.53', 'pretty_version' => 'v2.0.53',
'version' => '2.0.53.0', 'version' => '2.0.53.0',
'reference' => '06783eda65547a70ea686360a897759e1f873fff',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../topthink/think-orm', 'install_path' => __DIR__ . '/../topthink/think-orm',
'aliases' => array(), 'aliases' => array(),
'reference' => '06783eda65547a70ea686360a897759e1f873fff',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'topthink/think-template' => array( 'topthink/think-template' => array(
'pretty_version' => 'v2.0.8', 'pretty_version' => 'v2.0.8',
'version' => '2.0.8.0', 'version' => '2.0.8.0',
'reference' => 'abfc293f74f9ef5127b5c416310a01fe42e59368',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../topthink/think-template', 'install_path' => __DIR__ . '/../topthink/think-template',
'aliases' => array(), 'aliases' => array(),
'reference' => 'abfc293f74f9ef5127b5c416310a01fe42e59368',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'vlucas/phpdotenv' => array( 'vlucas/phpdotenv' => array(
'pretty_version' => 'v5.4.1', 'pretty_version' => 'v5.4.1',
'version' => '5.4.1.0', 'version' => '5.4.1.0',
'reference' => '264dce589e7ce37a7ba99cb901eed8249fbec92f',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../vlucas/phpdotenv', 'install_path' => __DIR__ . '/../vlucas/phpdotenv',
'aliases' => array(), 'aliases' => array(),
'reference' => '264dce589e7ce37a7ba99cb901eed8249fbec92f',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'voku/portable-ascii' => array( 'voku/portable-ascii' => array(
'pretty_version' => '1.6.1', 'pretty_version' => '1.6.1',
'version' => '1.6.1.0', 'version' => '1.6.1.0',
'reference' => '87337c91b9dfacee02452244ee14ab3c43bc485a',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../voku/portable-ascii', 'install_path' => __DIR__ . '/../voku/portable-ascii',
'aliases' => array(), 'aliases' => array(),
'reference' => '87337c91b9dfacee02452244ee14ab3c43bc485a',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'webman/action-hook' => array( 'webman/action-hook' => array(
'pretty_version' => 'v1.0.1', 'pretty_version' => 'v1.0.1',
'version' => '1.0.1.0', 'version' => '1.0.1.0',
'reference' => 'f5c0928f349eeb576b4208100d06d271bd4178b8',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../webman/action-hook', 'install_path' => __DIR__ . '/../webman/action-hook',
'aliases' => array(), 'aliases' => array(),
'reference' => 'f5c0928f349eeb576b4208100d06d271bd4178b8',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'webman/auto-route' => array( 'webman/auto-route' => array(
'pretty_version' => 'v1.0.2', 'pretty_version' => 'v1.0.2',
'version' => '1.0.2.0', 'version' => '1.0.2.0',
'reference' => 'd3cf4ad8c182baf08572255268993753554dc94b',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../webman/auto-route', 'install_path' => __DIR__ . '/../webman/auto-route',
'aliases' => array(), 'aliases' => array(),
'reference' => 'd3cf4ad8c182baf08572255268993753554dc94b', 'dev_requirement' => false,
),
'webman/console' => array(
'pretty_version' => 'v1.0.27',
'version' => '1.0.27.0',
'reference' => 'e450967eaabc43eb0c93cfcd6d8f420c16e22b67',
'type' => 'library',
'install_path' => __DIR__ . '/../webman/console',
'aliases' => array(),
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'webman/think-cache' => array( 'webman/think-cache' => array(
'pretty_version' => 'v1.0.1', 'pretty_version' => 'v1.0.1',
'version' => '1.0.1.0', 'version' => '1.0.1.0',
'reference' => '25bd103d7fc9347aca680e677282db761cc90a43',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../webman/think-cache', 'install_path' => __DIR__ . '/../webman/think-cache',
'aliases' => array(), 'aliases' => array(),
'reference' => '25bd103d7fc9347aca680e677282db761cc90a43',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'webman/think-orm' => array( 'webman/think-orm' => array(
'pretty_version' => 'v1.0.2', 'pretty_version' => 'v1.0.2',
'version' => '1.0.2.0', 'version' => '1.0.2.0',
'reference' => '5c686ecbdfbc99141d129aebd626cb8ded04830e',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../webman/think-orm', 'install_path' => __DIR__ . '/../webman/think-orm',
'aliases' => array(), 'aliases' => array(),
'reference' => '5c686ecbdfbc99141d129aebd626cb8ded04830e',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'workerman/validation' => array( 'workerman/validation' => array(
'pretty_version' => 'v3.0.2', 'pretty_version' => 'v3.0.2',
'version' => '3.0.2.0', 'version' => '3.0.2.0',
'reference' => '49387fff74acb63277ea7ed9a476ffe339348772',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../workerman/validation', 'install_path' => __DIR__ . '/../workerman/validation',
'aliases' => array(), 'aliases' => array(),
'reference' => '49387fff74acb63277ea7ed9a476ffe339348772',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'workerman/webman' => array( 'workerman/webman' => array(
'pretty_version' => 'dev-master', 'pretty_version' => '1.0.0+no-version-set',
'version' => 'dev-master', 'version' => '1.0.0.0',
'reference' => NULL,
'type' => 'project', 'type' => 'project',
'install_path' => __DIR__ . '/../../', 'install_path' => __DIR__ . '/../../',
'aliases' => array(), 'aliases' => array(),
'reference' => '8328e092da79093ae4d0d8e87589ad419cedf7a8',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'workerman/webman-framework' => array( 'workerman/webman-framework' => array(
'pretty_version' => 'v1.3.12', 'pretty_version' => 'v1.4.3',
'version' => '1.3.12.0', 'version' => '1.4.3.0',
'reference' => '0f4d5b6c58823656bdc9603f762d4be6e41ae380',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../workerman/webman-framework', 'install_path' => __DIR__ . '/../workerman/webman-framework',
'aliases' => array(), 'aliases' => array(),
'reference' => 'a5b392e68a88993e2c94f73805630458b6058c01',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'workerman/workerman' => array( 'workerman/workerman' => array(
'pretty_version' => 'v4.0.35', 'pretty_version' => 'v4.0.35',
'version' => '4.0.35.0', 'version' => '4.0.35.0',
'reference' => '1d8b3f7f9a7cef3e9f655b6151c7e93061ace397',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../workerman/workerman', 'install_path' => __DIR__ . '/../workerman/workerman',
'aliases' => array(), 'aliases' => array(),
'reference' => '1d8b3f7f9a7cef3e9f655b6151c7e93061ace397',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
), ),
......
build
vendor
.idea
.vscode
.phpunit*
composer.lock
\ No newline at end of file
# console
webman console
https://www.workerman.net/plugin/1
{
"name": "webman/console",
"type": "library",
"keywords": [
"webman console"
],
"homepage": "http://www.workerman.net",
"license": "MIT",
"description": "Webman console",
"authors": [
{
"name": "walkor",
"email": "walkor@workerman.net",
"homepage": "http://www.workerman.net",
"role": "Developer"
}
],
"support": {
"email": "walkor@workerman.net",
"issues": "https://github.com/webman-php/console/issues",
"forum": "http://www.workerman.net/questions",
"wiki": "http://www.workerman.net/doc/webman",
"source": "https://github.com/webman-php/console"
},
"require": {
"symfony/console": ">=5.0"
},
"autoload": {
"psr-4": {
"Webman\\Console\\" : "src"
}
},
"require-dev": {
"workerman/webman": "^1.0"
}
}
<?php
namespace Webman\Console;
use support\Container;
use support\Log;
use support\Request;
use Webman\App;
use Webman\Config;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http;
use Workerman\Worker;
use Dotenv\Dotenv;
ini_set('display_errors', 'on');
error_reporting(E_ALL);
class Application
{
public static function run()
{
$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.");
}
}
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::reload(config_path(), ['route', 'container']);
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 (property_exists(Worker::class, 'stopTimeout')) {
Worker::$stopTimeout = $config['stop_timeout'] ?? 2;
}
if ($config['listen']) {
$worker = new Worker($config['listen'], $config['context']);
$property_map = [
'name',
'count',
'user',
'group',
'reusePort',
'transport',
'protocol'
];
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) {
// Remove monitor process.
if (class_exists(\Phar::class, false) && \Phar::running() && 'monitor' === $process_name) {
continue;
}
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();
}
}
<?php
namespace Webman\Console;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Command\Command as Commands;
class Command extends Application
{
public function installInternalCommands()
{
$this->installCommands(__DIR__ . '/Commands', 'Webman\Console\Commands');
}
public function installCommands($path, $namspace = 'app\command')
{
$dir_iterator = new \RecursiveDirectoryIterator($path);
$iterator = new \RecursiveIteratorIterator($dir_iterator);
foreach ($iterator as $file) {
if (is_dir($file)) {
continue;
}
$class_name = $namspace.'\\'.basename($file, '.php');
if (!is_a($class_name, Commands::class, true)) {
continue;
}
$this->add(new $class_name);
}
}
}
<?php
namespace Webman\Console\Commands;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Webman\Console\Application;
class ConnectionsCommand extends Command
{
protected static $defaultName = 'connections';
protected static $defaultDescription = 'Get worker connections.';
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
if (\class_exists(\Support\App::class)) {
\Support\App::run();
return self::SUCCESS;
}
Application::run();
return self::SUCCESS;
}
}
<?php
namespace Webman\Console\Commands;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class InstallCommand extends Command
{
protected static $defaultName = 'install';
protected static $defaultDescription = 'Execute webman installation script';
/**
* @return void
*/
protected function configure()
{
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$output->writeln("Execute installation for webman");
$install_function = "\\Webman\\Install::install";
if (is_callable($install_function)) {
$install_function();
return self::SUCCESS;
}
$output->writeln('<error>This command requires webman-framework version >= 1.3.0</error>');
return self::FAILURE;
}
}
<?php
namespace Webman\Console\Commands;
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 Webman\Console\Util;
class MakeBootstrapCommand extends Command
{
protected static $defaultName = 'make:bootstrap';
protected static $defaultDescription = 'Make bootstrap';
/**
* @return void
*/
protected function configure()
{
$this->addArgument('name', InputArgument::REQUIRED, 'Bootstrap name');
$this->addArgument('enable', InputArgument::OPTIONAL, 'Enable or not');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$name = $input->getArgument('name');
$enable = in_array($input->getArgument('enable'), ['no', '0', 'false', 'n']) ? false : true;
$output->writeln("Make bootstrap $name");
$name = str_replace('\\', '/', $name);
if (!$bootstrap_str = Util::guessPath(app_path(), 'bootstrap')) {
$bootstrap_str = Util::guessPath(app_path(), 'controller') === 'Controller' ? 'Bootstrap' : 'bootstrap';
}
$upper = $bootstrap_str === 'Bootstrap';
if (!($pos = strrpos($name, '/'))) {
$name = ucfirst($name);
$file = app_path() . "/$bootstrap_str/$name.php";
$namespace = $upper ? 'App\Bootstrap' : 'app\bootstrap';
} else {
if($real_name = Util::guessPath(app_path(), $name)) {
$name = $real_name;
}
if ($upper && !$real_name) {
$name = preg_replace_callback('/\/([a-z])/', function ($matches) {
return '/' . strtoupper($matches[1]);
}, ucfirst($name));
}
$path = "$bootstrap_str/" . substr($upper ? ucfirst($name) : $name, 0, $pos);
$name = ucfirst(substr($name, $pos + 1));
$file = app_path() . "/$path/$name.php";
$namespace = str_replace('/', '\\', ($upper ? 'App/' : 'app/') . $path);
}
$this->createBootstrap($name, $namespace, $file);
if ($enable) {
$this->addConfig("$namespace\\$name", config_path() . '/bootstrap.php');
}
return self::SUCCESS;
}
/**
* @param $name
* @param $namespace
* @param $file
* @return void
*/
protected function createBootstrap($name, $namespace, $file)
{
$path = pathinfo($file, PATHINFO_DIRNAME);
if (!is_dir($path)) {
mkdir($path, 0777, true);
}
$bootstrap_content = <<<EOF
<?php
namespace $namespace;
use Webman\Bootstrap;
class $name implements Bootstrap
{
public static function start(\$worker)
{
// Is it console environment ?
\$is_console = !\$worker;
if (\$is_console) {
// If you do not want to execute this in console, just return.
return;
}
}
}
EOF;
file_put_contents($file, $bootstrap_content);
}
public function addConfig($class, $config_file)
{
$config = include $config_file;
if(!in_array($class, $config ?? [])) {
$config_file_content = file_get_contents($config_file);
$config_file_content = preg_replace('/\];/', " $class::class,\n];", $config_file_content);
file_put_contents($config_file, $config_file_content);
}
}
}
<?php
namespace Webman\Console\Commands;
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 Webman\Console\Util;
class MakeCommandCommand extends Command
{
protected static $defaultName = 'make:command';
protected static $defaultDescription = 'Make command';
/**
* @return void
*/
protected function configure()
{
$this->addArgument('name', InputArgument::REQUIRED, 'Command name');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$command = $name = $input->getArgument('name');
$output->writeln("Make command $name");
// make:command 不支持子目录
$name = str_replace(['\\', '/'], '', $name);
if (!$command_str = Util::guessPath(app_path(), 'command')) {
$command_str = Util::guessPath(app_path(), 'controller') === 'Controller' ? 'Command' : 'command';
}
$upper = $command_str === 'Command';
$name = ucfirst($name);
$file = app_path() . "/$command_str/$name.php";
$namespace = $upper ? 'App\Command' : 'app\command';
$this->createCommand($name, $namespace, $file, $command);
return self::SUCCESS;
}
protected function getClassName($name)
{
return preg_replace_callback('/:([a-zA-Z])/', function ($matches) {
return strtoupper($matches[1]);
}, ucfirst($name)) . 'Command';
}
/**
* @param $name
* @param $namespace
* @param $path
* @return void
*/
protected function createCommand($name, $namespace, $file, $command)
{
$path = pathinfo($file, PATHINFO_DIRNAME);
if (!is_dir($path)) {
mkdir($path, 0777, true);
}
$desc = str_replace(':', ' ', $command);
$command_content = <<<EOF
<?php
namespace $namespace;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Output\OutputInterface;
class $name extends Command
{
protected static \$defaultName = '$command';
protected static \$defaultDescription = '$desc';
/**
* @return void
*/
protected function configure()
{
\$this->addArgument('name', InputArgument::OPTIONAL, 'Name description');
}
/**
* @param InputInterface \$input
* @param OutputInterface \$output
* @return int
*/
protected function execute(InputInterface \$input, OutputInterface \$output)
{
\$name = \$input->getArgument('name');
\$output->writeln('Hello $command');
return self::SUCCESS;
}
}
EOF;
file_put_contents($file, $command_content);
}
}
<?php
namespace Webman\Console\Commands;
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 Webman\Console\Util;
class MakeControllerCommand extends Command
{
protected static $defaultName = 'make:controller';
protected static $defaultDescription = 'Make controller';
/**
* @return void
*/
protected function configure()
{
$this->addArgument('name', InputArgument::REQUIRED, 'Controller name');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$name = $input->getArgument('name');
$output->writeln("Make controller $name");
$suffix = config('app.controller_suffix', '');
if ($suffix && !strpos($name, $suffix)) {
$name .= $suffix;
}
$name = str_replace('\\', '/', $name);
if (!($pos = strrpos($name, '/'))) {
$name = ucfirst($name);
$controller_str = Util::guessPath(app_path(), 'controller') ?: 'controller';
$file = app_path() . "/$controller_str/$name.php";
$namespace = $controller_str === 'Controller' ? 'App\Controller' : 'app\controller';
} else {
$name_str = substr($name, 0, $pos);
if($real_name_str = Util::guessPath(app_path(), $name_str)) {
$name_str = $real_name_str;
} else if ($real_section_name = Util::guessPath(app_path(), strstr($name_str, '/', true))) {
$upper = strtolower($real_section_name[0]) !== $real_section_name[0];
} else if ($real_base_controller = Util::guessPath(app_path(), 'controller')) {
$upper = strtolower($real_base_controller[0]) !== $real_base_controller[0];
}
$upper = $upper ?? strtolower($name_str[0]) !== $name_str[0];
if ($upper && !$real_name_str) {
$name_str = preg_replace_callback('/\/([a-z])/', function ($matches) {
return '/' . strtoupper($matches[1]);
}, ucfirst($name_str));
}
$path = "$name_str/" . ($upper ? 'Controller' : 'controller');
$name = ucfirst(substr($name, $pos + 1));
$file = app_path() . "/$path/$name.php";
$namespace = str_replace('/', '\\', ($upper ? 'App/' : 'app/') . $path);
}
$this->createController($name, $namespace, $file);
return self::SUCCESS;
}
/**
* @param $name
* @param $namespace
* @param $file
* @return void
*/
protected function createController($name, $namespace, $file)
{
$path = pathinfo($file, PATHINFO_DIRNAME);
if (!is_dir($path)) {
mkdir($path, 0777, true);
}
$controller_content = <<<EOF
<?php
namespace $namespace;
use support\Request;
class $name
{
public function index(Request \$request)
{
return response(__CLASS__);
}
}
EOF;
file_put_contents($file, $controller_content);
}
}
<?php
namespace Webman\Console\Commands;
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 Webman\Console\Util;
class MakeMiddlewareCommand extends Command
{
protected static $defaultName = 'make:middleware';
protected static $defaultDescription = 'Make middleware';
/**
* @return void
*/
protected function configure()
{
$this->addArgument('name', InputArgument::REQUIRED, 'Middleware name');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$name = $input->getArgument('name');
$output->writeln("Make middleware $name");
$name = str_replace('\\', '/', $name);
if (!$middleware_str = Util::guessPath(app_path(), 'middleware')) {
$middleware_str = Util::guessPath(app_path(), 'controller') === 'Controller' ? 'Middleware' : 'middleware';
}
$upper = $middleware_str === 'Middleware';
if (!($pos = strrpos($name, '/'))) {
$name = ucfirst($name);
$file = app_path() . "/$middleware_str/$name.php";
$namespace = $upper ? 'App\Middleware' : 'app\middleware';
} else {
if($real_name = Util::guessPath(app_path(), $name)) {
$name = $real_name;
}
if ($upper && !$real_name) {
$name = preg_replace_callback('/\/([a-z])/', function ($matches) {
return '/' . strtoupper($matches[1]);
}, ucfirst($name));
}
$path = "$middleware_str/" . substr($upper ? ucfirst($name) : $name, 0, $pos);
$name = ucfirst(substr($name, $pos + 1));
$file = app_path() . "/$path/$name.php";
$namespace = str_replace('/', '\\', ($upper ? 'App/' : 'app/') . $path);
}
$this->createMiddleware($name, $namespace, $file);
return self::SUCCESS;
}
/**
* @param $name
* @param $namespace
* @param $path
* @return void
*/
protected function createMiddleware($name, $namespace, $file)
{
$path = pathinfo($file, PATHINFO_DIRNAME);
if (!is_dir($path)) {
mkdir($path, 0777, true);
}
$middleware_content = <<<EOF
<?php
namespace $namespace;
use Webman\MiddlewareInterface;
use Webman\Http\Response;
use Webman\Http\Request;
class $name implements MiddlewareInterface
{
public function process(Request \$request, callable \$next) : Response
{
return \$next(\$request);
}
}
EOF;
file_put_contents($file, $middleware_content);
}
}
<?php
namespace Webman\Console\Commands;
use Symfony\Component\Console\Command\Command;
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 Webman\Console\Util;
class MakeModelCommand extends Command
{
protected static $defaultName = 'make:model';
protected static $defaultDescription = 'Make model';
/**
* @return void
*/
protected function configure()
{
$this->addArgument('name', InputArgument::REQUIRED, 'Model name');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$name = $input->getArgument('name');
$name = Util::nameToClass($name);
$output->writeln("Make model $name");
if (!($pos = strrpos($name, '/'))) {
$name = ucfirst($name);
$model_str = Util::guessPath(app_path(), 'model') ?: 'model';
$file = app_path() . "/$model_str/$name.php";
$namespace = $model_str === 'Model' ? 'App\Model' : 'app\model';
} else {
$name_str = substr($name, 0, $pos);
if($real_name_str = Util::guessPath(app_path(), $name_str)) {
$name_str = $real_name_str;
} else if ($real_section_name = Util::guessPath(app_path(), strstr($name_str, '/', true))) {
$upper = strtolower($real_section_name[0]) !== $real_section_name[0];
} else if ($real_base_controller = Util::guessPath(app_path(), 'controller')) {
$upper = strtolower($real_base_controller[0]) !== $real_base_controller[0];
}
$upper = $upper ?? strtolower($name_str[0]) !== $name_str[0];
if ($upper && !$real_name_str) {
$name_str = preg_replace_callback('/\/([a-z])/', function ($matches) {
return '/' . strtoupper($matches[1]);
}, ucfirst($name_str));
}
$path = "$name_str/" . ($upper ? 'Model' : 'model');
$name = ucfirst(substr($name, $pos + 1));
$file = app_path() . "/$path/$name.php";
$namespace = str_replace('/', '\\', ($upper ? 'App/' : 'app/') . $path);
}
if (!config('database') && config('thinkorm')) {
$this->createTpModel($name, $namespace, $file);
} else {
$this->createModel($name, $namespace, $file);
}
return self::SUCCESS;
}
/**
* @param $class
* @param $namespace
* @param $file
* @return void
*/
protected function createModel($class, $namespace, $file)
{
$path = pathinfo($file, PATHINFO_DIRNAME);
if (!is_dir($path)) {
mkdir($path, 0777, true);
}
$table = Util::classToName($class);
$table_val = 'null';
$pk = 'id';
$properties = '';
try {
$prefix = config('database.connections.mysql.prefix') ?? '';
$database = config('database.connections.mysql.database');
if (\support\Db::select("show tables like '{$prefix}{$table}s'")) {
$table = "{$prefix}{$table}s";
} else if (\support\Db::select("show tables like '{$prefix}{$table}'")) {
$table_val = "'$table'";
$table = "{$prefix}{$table}";
}
foreach (\support\Db::select("select COLUMN_NAME,DATA_TYPE,COLUMN_KEY,COLUMN_COMMENT from INFORMATION_SCHEMA.COLUMNS where table_name = '$table' and table_schema = '$database'") as $item) {
if ($item->COLUMN_KEY === 'PRI') {
$pk = $item->COLUMN_NAME;
$item->COLUMN_COMMENT .= "(主键)";
}
$type = $this->getType($item->DATA_TYPE);
$properties .= " * @property $type \${$item->COLUMN_NAME} {$item->COLUMN_COMMENT}\n";
}
} catch (\Throwable $e) {}
$properties = rtrim($properties) ?: ' *';
$model_content = <<<EOF
<?php
namespace $namespace;
use support\Model;
/**
$properties
*/
class $class extends Model
{
/**
* The table associated with the model.
*
* @var string
*/
protected \$table = $table_val;
/**
* The primary key associated with the table.
*
* @var string
*/
protected \$primaryKey = '$pk';
/**
* Indicates if the model should be timestamped.
*
* @var bool
*/
public \$timestamps = false;
}
EOF;
file_put_contents($file, $model_content);
}
/**
* @param $class
* @param $namespace
* @param $path
* @return void
*/
protected function createTpModel($class, $namespace, $file)
{
$path = pathinfo($file, PATHINFO_DIRNAME);
if (!is_dir($path)) {
mkdir($path, 0777, true);
}
$table = Util::classToName($class);
$table_val = 'null';
$pk = 'id';
$properties = '';
try {
$prefix = config('thinkorm.connections.mysql.prefix') ?? '';
$database = config('thinkorm.connections.mysql.database');
if (\think\facade\Db::query("show tables like '{$prefix}{$table}'")) {
$table = "{$prefix}{$table}";
$table_val = "'$table'";
} else if (\think\facade\Db::query("show tables like '{$prefix}{$table}s'")) {
$table = "{$prefix}{$table}s";
$table_val = "'$table'";
}
foreach (\think\facade\Db::query("select COLUMN_NAME,DATA_TYPE,COLUMN_KEY,COLUMN_COMMENT from INFORMATION_SCHEMA.COLUMNS where table_name = '$table' and table_schema = '$database'") as $item) {
if ($item['COLUMN_KEY'] === 'PRI') {
$pk = $item['COLUMN_NAME'];
$item['COLUMN_COMMENT'] .= "(主键)";
}
$type = $this->getType($item['DATA_TYPE']);
$properties .= " * @property $type \${$item['COLUMN_NAME']} {$item['COLUMN_COMMENT']}\n";
}
} catch (\Throwable $e) {}
$properties = rtrim($properties) ?: ' *';
$model_content = <<<EOF
<?php
namespace $namespace;
use think\Model;
/**
$properties
*/
class $class extends Model
{
/**
* The table associated with the model.
*
* @var string
*/
protected \$table = $table_val;
/**
* The primary key associated with the table.
*
* @var string
*/
protected \$pk = '$pk';
}
EOF;
file_put_contents($file, $model_content);
}
/**
* @param string $type
* @return string
*/
protected function getType(string $type)
{
if (strpos($type, 'int') !== false) {
return 'integer';
}
switch ($type) {
case 'varchar':
case 'string':
case 'text':
case 'date':
case 'time':
case 'guid':
case 'datetimetz':
case 'datetime':
case 'decimal':
case 'enum':
return 'string';
case 'boolean':
return 'integer';
case 'float':
return 'float';
default:
return 'mixed';
}
}
}
<?php
namespace Webman\Console\Commands;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Phar;
use RuntimeException;
class PharPackCommand extends Command
{
protected static $defaultName = 'phar:pack';
protected static $defaultDescription = 'Can be easily packaged a project into phar files. Easy to distribute and use.';
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$this->checkEnv();
$phar_file_output_dir = config('plugin.webman.console.app.phar_file_output_dir');
if (empty($phar_file_output_dir)) {
throw new RuntimeException('Please set the phar file output directory.');
}
if (!file_exists($phar_file_output_dir) && !is_dir($phar_file_output_dir)) {
if (!mkdir($phar_file_output_dir,0777,true)) {
throw new RuntimeException("Failed to create phar file output directory. Please check the permission.");
}
}
$phar_filename = config('plugin.webman.console.app.phar_filename');
if (empty($phar_filename)) {
throw new RuntimeException('Please set the phar filename.');
}
$phar_file = rtrim($phar_file_output_dir,DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $phar_filename;
if (file_exists($phar_file)) {
unlink($phar_file);
}
$exclude_pattern = config('plugin.webman.console.app.exclude_pattern');
$phar = new Phar($phar_file,0,'webman');
$phar->startBuffering();
$signature_algorithm = config('plugin.webman.console.app.signature_algorithm');
if (!in_array($signature_algorithm,[Phar::MD5, Phar::SHA1, Phar::SHA256, Phar::SHA512,Phar::OPENSSL])) {
throw new RuntimeException('The signature algorithm must be one of Phar::MD5, Phar::SHA1, Phar::SHA256, Phar::SHA512, or Phar::OPENSSL.');
}
if ($signature_algorithm === Phar::OPENSSL) {
$private_key_file = config('plugin.webman.console.app.private_key_file');
if (!file_exists($private_key_file)) {
throw new RuntimeException("If the value of the signature algorithm is 'Phar::OPENSSL', you must set the private key file.");
}
$private = openssl_get_privatekey(file_get_contents($private_key_file));
$pkey = '';
openssl_pkey_export($private, $pkey);
$phar->setSignatureAlgorithm($signature_algorithm, $pkey);
} else {
$phar->setSignatureAlgorithm($signature_algorithm);
}
$phar->buildFromDirectory(BASE_PATH,$exclude_pattern);
$exclude_files = config('plugin.webman.console.app.exclude_files');
foreach ($exclude_files as $file) {
if($phar->offsetExists($file)){
$phar->delete($file);
}
}
$output->writeln('Files collect complete, begin add file to Phar.');
$phar->setStub("#!/usr/bin/env php
<?php
define('IN_PHAR', true);
Phar::mapPhar('webman');
require 'phar://webman/webman';
__HALT_COMPILER();
");
$output->writeln('Write requests to the Phar archive, save changes to disk.');
$phar->stopBuffering();
unset($phar);
return self::SUCCESS;
}
/**
* @throws RuntimeException
*/
private function checkEnv(): void
{
if (!class_exists(Phar::class, false)) {
throw new RuntimeException("The 'phar' extension is required for build phar package");
}
if (ini_get('phar.readonly')) {
throw new RuntimeException(
"The 'phar.readonly' is 'On', build phar must setting it 'Off' or exec with 'php -d phar.readonly=0 ./webman phar:pack'"
);
}
}
}
<?php
namespace Webman\Console\Commands;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputOption;
use Webman\Console\Util;
class PluginCreateCommand extends Command
{
protected static $defaultName = 'plugin:create';
protected static $defaultDescription = 'Plugin create';
/**
* @return void
*/
protected function configure()
{
$this->addOption('name', 'name', InputOption::VALUE_REQUIRED, 'Plugin name, for example foo/my-admin');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$name = strtolower($input->getOption('name'));
$output->writeln("Create Plugin $name");
if (!strpos($name, '/')) {
$output->writeln('<error>Bad name, name must contain character \'/\' , for example foo/MyAdmin</error>');
return self::FAILURE;
}
$namespace = Util::nameToNamespace($name);
// Create dir config/plugin/$name
if (is_dir($plugin_config_path = config_path()."/plugin/$name")) {
$output->writeln("<error>Dir $plugin_config_path already exists</error>");
return self::FAILURE;
}
if (is_dir($plugin_path = base_path()."/vendor/$name")) {
$output->writeln("<error>Dir $plugin_path already exists</error>");
return self::FAILURE;
}
// Add psr-4
if ($err = $this->addAutoloadToComposerJson($name, $namespace)) {
$output->writeln("<error>$err</error>");
return self::FAILURE;
}
$this->createConfigFiles($plugin_config_path);
$this->createVendorFiles($name, $namespace, $plugin_path, $output);
return self::SUCCESS;
}
protected function addAutoloadToComposerJson($name, $namespace)
{
if (!is_file($composer_json_file = base_path()."/composer.json")) {
return "$composer_json_file not exists";
}
$composer_json = json_decode($composer_json_str = file_get_contents($composer_json_file), true);
if (!$composer_json) {
return "Bad $composer_json_file";
}
if(isset($composer_json['autoload']['psr-4'][$namespace."\\"])) {
return;
}
$namespace = str_replace("\\", "\\\\", $namespace);
$composer_json_str = str_replace('"psr-4": {', '"psr-4": {'."\n \"$namespace\\\\\" : \"vendor/$name/src\",", $composer_json_str);
file_put_contents($composer_json_file, $composer_json_str);
}
protected function createConfigFiles($plugin_config_path)
{
mkdir($plugin_config_path, 0777, true);
$app_str = <<<EOF
<?php
return [
'enable' => true,
];
EOF;
file_put_contents("$plugin_config_path/app.php", $app_str);
}
protected function createVendorFiles($name, $namespace, $plugin_path, $output)
{
mkdir("$plugin_path/src", 0777, true);
$this->createComposerJson($name, $namespace, $plugin_path);
if (is_callable('exec')) {
exec("composer dumpautoload");
} else {
$output->writeln("<info>Please run command 'composer dumpautoload'</info>");
}
}
/**
* @param $name
* @param $namespace
* @param $dest
* @return void
*/
protected function createComposerJson($name, $namespace, $dest)
{
$namespace = str_replace('\\', '\\\\', $namespace);
$composer_json_content = <<<EOT
{
"name": "$name",
"type": "library",
"license": "MIT",
"description": "Webman plugin $name",
"require": {
},
"autoload": {
"psr-4": {
"$namespace\\\\": "src"
}
}
}
EOT;
file_put_contents("$dest/composer.json", $composer_json_content);
}
/**
* @param $namespace
* @param $path_relations
* @param $dest_dir
* @return void
*/
protected function writeInstallFile($namespace, $path_relations, $dest_dir)
{
if (!is_dir($dest_dir)) {
mkdir($dest_dir, 0777, true);
}
$relations = [];
foreach($path_relations as $relation) {
$relations[$relation] = $relation;
}
$relations = var_export($relations, true);
$install_php_content = <<<EOT
<?php
namespace $namespace;
class Install
{
const WEBMAN_PLUGIN = true;
/**
* @var array
*/
protected static \$pathRelation = $relations;
/**
* Install
* @return void
*/
public static function install()
{
static::installByRelation();
}
/**
* Uninstall
* @return void
*/
public static function uninstall()
{
self::uninstallByRelation();
}
/**
* installByRelation
* @return void
*/
public static function installByRelation()
{
foreach (static::\$pathRelation as \$source => \$dest) {
if (\$pos = strrpos(\$dest, '/')) {
\$parent_dir = base_path().'/'.substr(\$dest, 0, \$pos);
if (!is_dir(\$parent_dir)) {
mkdir(\$parent_dir, 0777, true);
}
}
//symlink(__DIR__ . "/\$source", base_path()."/\$dest");
copy_dir(__DIR__ . "/\$source", base_path()."/\$dest");
}
}
/**
* uninstallByRelation
* @return void
*/
public static function uninstallByRelation()
{
foreach (static::\$pathRelation as \$source => \$dest) {
/*if (is_link(base_path()."/\$dest")) {
unlink(base_path()."/\$dest");
}*/
remove_dir(base_path()."/\$dest");
}
}
}
EOT;
file_put_contents("$dest_dir/Install.php", $install_php_content);
}
}
<?php
namespace Webman\Console\Commands;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputArgument;
class PluginDisableCommand extends Command
{
protected static $defaultName = 'plugin:disable';
protected static $defaultDescription = 'Disable plugin by name';
/**
* @return void
*/
protected function configure()
{
$this->addArgument('name', InputArgument::REQUIRED, 'Plugin name, for example foo/my-admin');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$name = $input->getArgument('name');
$output->writeln("Disable plugin $name");
if (!strpos($name, '/')) {
$output->writeln('<error>Bad name, name must contain character \'/\' , for example foo/MyAdmin</error>');
return self::FAILURE;
}
$config_file = config_path() . "/plugin/$name/app.php";
if (!is_file($config_file)) {
return self::SUCCESS;
}
$config = include $config_file;
if (empty($config['enable'])) {
return self::SUCCESS;
}
$config_content = file_get_contents($config_file);
$config_content = preg_replace('/(\'enable\' *?=> *?)(true)/', '$1false', $config_content);
file_put_contents($config_file, $config_content);
return self::SUCCESS;
}
}
<?php
namespace Webman\Console\Commands;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputArgument;
class PluginEnableCommand extends Command
{
protected static $defaultName = 'plugin:enable';
protected static $defaultDescription = 'Enable plugin by name';
/**
* @return void
*/
protected function configure()
{
$this->addArgument('name', InputArgument::REQUIRED, 'Plugin name, for example foo/my-admin');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$name = $input->getArgument('name');
$output->writeln("Enable plugin $name");
if (!strpos($name, '/')) {
$output->writeln('<error>Bad name, name must contain character \'/\' , for example foo/MyAdmin</error>');
return self::FAILURE;
}
$config_file = config_path() . "/plugin/$name/app.php";
if (!is_file($config_file)) {
$output->writeln("<error>$config_file not found</error>");
return self::FAILURE;
}
$config = include $config_file;
if (!isset($config['enable'])) {
$output->writeln("<error>Config key 'enable' not found</error>");
return self::FAILURE;
}
if ($config['enable']) {
return self::SUCCESS;
}
$config_content = file_get_contents($config_file);
$config_content = preg_replace('/(\'enable\' *?=> *?)(false)/', '$1true', $config_content);
file_put_contents($config_file, $config_content);
return self::SUCCESS;
}
}
<?php
namespace Webman\Console\Commands;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputOption;
use Webman\Console\Util;
class PluginExportCommand extends Command
{
protected static $defaultName = 'plugin:export';
protected static $defaultDescription = 'Plugin export';
/**
* @return void
*/
protected function configure()
{
$this->addOption('name', 'name', InputOption::VALUE_REQUIRED, 'Plugin name, for example foo/my-admin');
$this->addOption('source', 'source', InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Directories to export');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$output->writeln('Export Plugin');
$name = strtolower($input->getOption('name'));
if (!strpos($name, '/')) {
$output->writeln('<error>Bad name, name must contain character \'/\' , for example foo/MyAdmin</error>');
return self::INVALID;
}
$namespace = Util::nameToNamespace($name);
$path_relations = $input->getOption('source');
if (!in_array("config/plugin/$name", $path_relations)) {
if (is_dir("config/plugin/$name")) {
$path_relations[] = "config/plugin/$name";
}
}
$original_dest = $dest = base_path()."/vendor/$name";
$dest .= '/src';
$this->writeInstallFile($namespace, $path_relations, $dest);
$output->writeln("<info>Create $dest/Install.php</info>");
foreach ($path_relations as $source) {
$base_path = pathinfo("$dest/$source", PATHINFO_DIRNAME);
if (!is_dir($base_path)) {
mkdir($base_path, 0777, true);
}
$output->writeln("<info>Copy $source to $dest/$source </info>");
copy_dir($source, "$dest/$source");
}
$output->writeln("<info>Saved $name to $original_dest</info>");
return self::SUCCESS;
}
/**
* @param $namespace
* @param $path_relations
* @param $dest_dir
* @return void
*/
protected function writeInstallFile($namespace, $path_relations, $dest_dir)
{
if (!is_dir($dest_dir)) {
mkdir($dest_dir, 0777, true);
}
$relations = [];
foreach($path_relations as $relation) {
$relations[$relation] = $relation;
}
$relations = var_export($relations, true);
$install_php_content = <<<EOT
<?php
namespace $namespace;
class Install
{
const WEBMAN_PLUGIN = true;
/**
* @var array
*/
protected static \$pathRelation = $relations;
/**
* Install
* @return void
*/
public static function install()
{
static::installByRelation();
}
/**
* Uninstall
* @return void
*/
public static function uninstall()
{
self::uninstallByRelation();
}
/**
* installByRelation
* @return void
*/
public static function installByRelation()
{
foreach (static::\$pathRelation as \$source => \$dest) {
if (\$pos = strrpos(\$dest, '/')) {
\$parent_dir = base_path().'/'.substr(\$dest, 0, \$pos);
if (!is_dir(\$parent_dir)) {
mkdir(\$parent_dir, 0777, true);
}
}
//symlink(__DIR__ . "/\$source", base_path()."/\$dest");
copy_dir(__DIR__ . "/\$source", base_path()."/\$dest");
echo "Create \$dest\r\n";
}
}
/**
* uninstallByRelation
* @return void
*/
public static function uninstallByRelation()
{
foreach (static::\$pathRelation as \$source => \$dest) {
\$path = base_path()."/\$dest";
if (!is_dir(\$path) && !is_file(\$path)) {
continue;
}
echo "Remove \$dest\r\n";
if (is_file(\$path) || is_link(\$path)) {
unlink(\$path);
continue;
}
remove_dir(\$path);
}
}
}
EOT;
file_put_contents("$dest_dir/Install.php", $install_php_content);
}
}
<?php
namespace Webman\Console\Commands;
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 Webman\Console\Util;
class PluginInstallCommand extends Command
{
protected static $defaultName = 'plugin:install';
protected static $defaultDescription = 'Execute plugin installation script';
/**
* @return void
*/
protected function configure()
{
$this->addArgument('name', InputArgument::REQUIRED, 'Plugin name, for example foo/my-admin');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$name = $input->getArgument('name');
$output->writeln("Execute installation for plugin $name");
$namespace = Util::nameToNamespace($name);
$install_function = "\\{$namespace}\\Install::install";
$plugin_const = "\\{$namespace}\\Install::WEBMAN_PLUGIN";
if (defined($plugin_const) && is_callable($install_function)) {
$install_function();
}
return self::SUCCESS;
}
}
<?php
namespace Webman\Console\Commands;
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 Webman\Console\Util;
class PluginUninstallCommand extends Command
{
protected static $defaultName = 'plugin:uninstall';
protected static $defaultDescription = 'Execute plugin uninstall script';
/**
* @return void
*/
protected function configure()
{
$this->addArgument('name', InputArgument::REQUIRED, 'Plugin name, for example foo/my-admin');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$name = $input->getArgument('name');
$output->writeln("Execute uninstall for plugin $name");
if (!strpos($name, '/')) {
$output->writeln('<error>Bad name, name must contain character \'/\' , for example foo/MyAdmin</error>');
return self::FAILURE;
}
$namespace = Util::nameToNamespace($name);
$uninstall_function = "\\{$namespace}\\Install::uninstall";
$plugin_const = "\\{$namespace}\\Install::WEBMAN_PLUGIN";
if (defined($plugin_const) && is_callable($uninstall_function)) {
$uninstall_function();
}
return self::SUCCESS;
}
}
<?php
namespace Webman\Console\Commands;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputOption;
use Webman\Console\Application;
class ReStartCommand extends Command
{
protected static $defaultName = 'restart';
protected static $defaultDescription = 'Restart workers. Use mode -d to start in DAEMON mode. Use mode -g to stop gracefully.';
protected function configure() : void
{
$this
->addOption('daemon', 'd', InputOption::VALUE_NONE, 'DAEMON mode')
->addOption('graceful', 'g', InputOption::VALUE_NONE, 'graceful stop');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
if (\class_exists(\Support\App::class)) {
\Support\App::run();
return self::SUCCESS;
}
Application::run();
return self::SUCCESS;
}
}
<?php
namespace Webman\Console\Commands;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputOption;
use Webman\Console\Application;
class ReloadCommand extends Command
{
protected static $defaultName = 'reload';
protected static $defaultDescription = 'Reload codes. Use mode -g to reload gracefully.';
protected function configure() : void
{
$this
->addOption('graceful', 'd', InputOption::VALUE_NONE, 'graceful reload');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
if (\class_exists(\Support\App::class)) {
\Support\App::run();
return self::SUCCESS;
}
Application::run();
return self::SUCCESS;
}
}
<?php
namespace Webman\Console\Commands;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Helper\Table;
use Webman\Route;
class RouteListCommand extends Command
{
protected static $defaultName = 'route:list';
protected static $defaultDescription = 'Route list';
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$headers = ['uri', 'method', 'callback', 'middleware'];
$rows = [];
foreach (Route::getRoutes() as $route) {
foreach ($route->getMethods() as $method) {
$cb = $route->getCallback();
$cb = $cb instanceof \Closure ? 'Closure' : (is_array($cb) ? json_encode($cb) : var_export($cb, 1));
$rows[] = [$route->getPath(), $method, $cb, json_encode($route->getMiddleware() ?: null)];
}
}
$table = new Table($output);
$table->setHeaders($headers);
$table->setRows($rows);
$table->render();
return self::SUCCESS;
}
}
<?php
namespace Webman\Console\Commands;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputOption;
use Webman\Console\Application;
class StartCommand extends Command
{
protected static $defaultName = 'start';
protected static $defaultDescription = 'Start worker in DEBUG mode. Use mode -d to start in DAEMON mode.';
protected function configure() : void
{
$this->addOption('daemon', 'd', InputOption::VALUE_NONE, 'DAEMON mode');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
if (\class_exists(\Support\App::class)) {
\Support\App::run();
return self::SUCCESS;
}
Application::run();
return self::SUCCESS;
}
}
<?php
namespace Webman\Console\Commands;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputOption;
use Webman\Console\Application;
class StatusCommand extends Command
{
protected static $defaultName = 'status';
protected static $defaultDescription = 'Get worker status. Use mode -d to show live status.';
protected function configure() : void
{
$this->addOption('live', 'd', InputOption::VALUE_NONE, 'show live status');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
if (\class_exists(\Support\App::class)) {
\Support\App::run();
return self::SUCCESS;
}
Application::run();
return self::SUCCESS;
}
}
<?php
namespace Webman\Console\Commands;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputOption;
use Webman\Console\Application;
class StopCommand extends Command
{
protected static $defaultName = 'stop';
protected static $defaultDescription = 'Stop worker. Use mode -g to stop gracefully.';
protected function configure() : void
{
$this
->addOption('graceful', 'g',InputOption::VALUE_NONE, 'graceful stop');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
if (\class_exists(\Support\App::class)) {
\Support\App::run();
return self::SUCCESS;
}
Application::run();
return self::SUCCESS;
}
}
<?php
namespace Webman\Console\Commands;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class VersionCommand extends Command
{
protected static $defaultName = 'version';
protected static $defaultDescription = 'Show webman version';
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$installed_file = base_path() . '/vendor/composer/installed.php';
if (is_file($installed_file)) {
$version_info = include $installed_file;
}
$webman_framework_version = $version_info['versions']['workerman/webman-framework']['pretty_version'] ?? '';
$output->writeln("Webman-framework $webman_framework_version");
return self::SUCCESS;
}
}
<?php
namespace Webman\Console;
class Install
{
const WEBMAN_PLUGIN = true;
/**
* @var array
*/
protected static $pathRelation = array (
'config/plugin/webman/console' => 'config/plugin/webman/console',
);
/**
* Install
* @return void
*/
public static function install()
{
copy(__DIR__ . "/webman", base_path()."/webman");
chmod(base_path()."/webman", 0755);
static::installByRelation();
}
/**
* Uninstall
* @return void
*/
public static function uninstall()
{
if (is_file(base_path()."/webman")) {
unlink(base_path() . "/webman");
}
self::uninstallByRelation();
}
/**
* installByRelation
* @return void
*/
public static function installByRelation()
{
foreach (static::$pathRelation as $source => $dest) {
if ($pos = strrpos($dest, '/')) {
$parent_dir = base_path().'/'.substr($dest, 0, $pos);
if (!is_dir($parent_dir)) {
mkdir($parent_dir, 0777, true);
}
}
//symlink(__DIR__ . "/$source", base_path()."/$dest");
copy_dir(__DIR__ . "/$source", base_path()."/$dest");
}
}
/**
* uninstallByRelation
* @return void
*/
public static function uninstallByRelation()
{
foreach (static::$pathRelation as $source => $dest) {
$path = base_path()."/$dest";
if (!is_dir($path) && !is_file($path)) {
continue;
}
/*if (is_link($path) {
unlink($path);
}*/
remove_dir($path);
}
}
}
<?php
namespace Webman\Console;
class Util
{
public static function nameToNamespace($name)
{
$namespace = ucfirst($name);
$namespace = preg_replace_callback(['/-([a-zA-Z])/', '/(\/[a-zA-Z])/'], function ($matches) {
return strtoupper($matches[1]);
}, $namespace);
return str_replace('/', '\\' ,ucfirst($namespace));
}
public static function classToName($class)
{
$class = lcfirst($class);
return preg_replace_callback(['/([A-Z])/'], function ($matches) {
return '_' . strtolower($matches[1]);
}, $class);
}
public static function nameToClass($class)
{
$class = preg_replace_callback(['/-([a-zA-Z])/', '/_([a-zA-Z])/'], function ($matches) {
return strtoupper($matches[1]);
}, $class);
if (!($pos = strrpos($class, '/'))) {
$class = ucfirst($class);
} else {
$path = substr($class, 0, $pos);
$class = ucfirst(substr($class, $pos + 1));
$class = "$path/$class";
}
return $class;
}
public static function guessPath($base_path, $name, $return_full_path = false)
{
if (!is_dir($base_path)) {
return false;
}
$names = explode('/', trim(strtolower($name), '/'));
$realname = [];
$path = $base_path;
foreach ($names as $name) {
$finded = false;
foreach (scandir($path) ?: [] as $tmp_name) {
if (strtolower($tmp_name) === $name && is_dir("$path/$tmp_name")) {
$path = "$path/$tmp_name";
$realname[] = $tmp_name;
$finded = true;
break;
}
}
if (!$finded) {
return false;
}
}
$realname = implode(DIRECTORY_SEPARATOR, $realname);
return $return_full_path ? realpath($base_path . DIRECTORY_SEPARATOR . $realname) : $realname;
}
}
<?php
return [
'enable' => true,
'phar_file_output_dir' => BASE_PATH . DIRECTORY_SEPARATOR . 'build',
'phar_filename' => 'webman.phar',
'signature_algorithm'=> Phar::SHA256, //set the signature algorithm for a phar and apply it. The signature algorithm must be one of Phar::MD5, Phar::SHA1, Phar::SHA256, Phar::SHA512, or Phar::OPENSSL.
'private_key_file' => '', // The file path for certificate or OpenSSL private key file.
//'exclude_pattern' => '#^(?!.*(config/plugin/webman/console/app.php|webman/console/src/Commands/(PharPackCommand.php|ReloadCommand.php)|LICENSE|composer.json|.github|.idea|doc|docs|.git|.setting|runtime|test|test_old|tests|Tests|vendor-bin|.md))(.*)$#',
'exclude_files' => [
'.env', 'LICENSE', 'composer.json', 'composer.lock','start.php'
]
];
#!/usr/bin/env php
<?php
use Webman\Config;
use Webman\Console\Command;
use Webman\Console\Util;
require_once __DIR__ . '/vendor/autoload.php';
if (!in_array($argv[1] ?? '', ['start', 'restart', 'stop', 'status', 'reload', 'connections'])) {
require_once __DIR__ . '/support/bootstrap.php';
} else {
if (class_exists('Support\App')) {
Support\App::loadAllConfig(['route']);
} else {
Config::reload(config_path(), ['route', 'container']);
}
}
$cli = new Command();
$cli->setName('webman cli');
$cli->installInternalCommands();
if (is_dir($command_path = Util::guessPath(app_path(), '/command', true))) {
$cli->installCommands($command_path);
}
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 ($projects as $name => $project) {
if (!is_array($project)) {
continue;
}
foreach ($project['command'] ?? [] as $command) {
$cli->add(new $command);
}
}
}
$cli->run();
...@@ -14,17 +14,19 @@ ...@@ -14,17 +14,19 @@
namespace Webman; namespace Webman;
use Workerman\Worker; use Closure;
use Workerman\Connection\TcpConnection; use FastRoute\Dispatcher;
use Monolog\Logger;
use Psr\Container\ContainerInterface;
use Throwable;
use Webman\Exception\ExceptionHandler;
use Webman\Exception\ExceptionHandlerInterface;
use Webman\Http\Request; use Webman\Http\Request;
use Webman\Http\Response; use Webman\Http\Response;
use Webman\Route\Route as RouteObject; use Webman\Route\Route as RouteObject;
use Webman\Exception\ExceptionHandlerInterface; use Workerman\Connection\TcpConnection;
use Webman\Exception\ExceptionHandler; use Workerman\Protocols\Http;
use Webman\Config; use Workerman\Worker;
use FastRoute\Dispatcher;
use Psr\Container\ContainerInterface;
use Monolog\Logger;
/** /**
* Class App * Class App
...@@ -33,16 +35,6 @@ use Monolog\Logger; ...@@ -33,16 +35,6 @@ use Monolog\Logger;
class App class App
{ {
/**
* @var bool
*/
protected static $_supportStaticFiles = true;
/**
* @var bool
*/
protected static $_supportPHPFiles = false;
/** /**
* @var array * @var array
*/ */
...@@ -89,33 +81,24 @@ class App ...@@ -89,33 +81,24 @@ class App
protected static $_request = null; protected static $_request = null;
/** /**
* @var int * @var string
*/ */
protected static $_gracefulStopTimer = null; protected static $_requestClass = '';
/** /**
* App constructor. * App constructor.
* @param Worker $worker *
* @param $container * @param string $request_class
* @param $logger * @param Logger $logger
* @param $app_path * @param string $app_path
* @param $public_path * @param string $public_path
*/ */
public function __construct(Worker $worker, $container, $logger, $app_path, $public_path) public function __construct(string $request_class, Logger $logger, string $app_path, string $public_path)
{ {
static::$_worker = $worker; static::$_requestClass = $request_class;
static::$_container = $container;
static::$_logger = $logger; static::$_logger = $logger;
static::$_publicPath = $public_path; static::$_publicPath = $public_path;
// Phar support. static::$_appPath = $app_path;
if (class_exists(\Phar::class, false) && \Phar::running()) {
static::$_appPath = $app_path;
} else {
static::$_appPath = \realpath($app_path);
}
static::$_supportStaticFiles = Config::get('static.enable', true);
static::$_supportPHPFiles = Config::get('app.support_php_files', false);
} }
/** /**
...@@ -123,7 +106,7 @@ class App ...@@ -123,7 +106,7 @@ class App
* @param Request $request * @param Request $request
* @return null * @return null
*/ */
public function onMessage(TcpConnection $connection, $request) public function onMessage($connection, $request)
{ {
try { try {
static::$_request = $request; static::$_request = $request;
...@@ -131,20 +114,14 @@ class App ...@@ -131,20 +114,14 @@ class App
$path = $request->path(); $path = $request->path();
$key = $request->method() . $path; $key = $request->method() . $path;
if (isset(static::$_callbacks[$key])) { if (isset(static::$_callbacks[$key])) {
[$callback, $request->app, $request->controller, $request->action, $request->route] = static::$_callbacks[$key]; [$callback, $request->plugin, $request->app, $request->controller, $request->action, $request->route] = static::$_callbacks[$key];
static::send($connection, $callback($request), $request); return static::send($connection, $callback($request), $request);
return null;
}
if (static::unsafeUri($path)) {
return null;
} }
if (static::findFile($connection, $path, $key, $request)) { if (static::unsafeUri($connection, $path, $request) ||
return null; static::findFile($connection, $path, $key, $request) ||
} static::findRoute($connection, $path, $key, $request)
) {
if (static::findRoute($connection, $path, $key, $request)) {
return null; return null;
} }
...@@ -155,26 +132,55 @@ class App ...@@ -155,26 +132,55 @@ class App
static::send($connection, $callback($request), $request); static::send($connection, $callback($request), $request);
return null; return null;
} }
$plugin = $controller_and_action['plugin'];
$app = $controller_and_action['app']; $app = $controller_and_action['app'];
$controller = $controller_and_action['controller']; $controller = $controller_and_action['controller'];
$action = $controller_and_action['action']; $action = $controller_and_action['action'];
$callback = static::getCallback($app, [$controller_and_action['instance'], $action]); $callback = static::getCallback($plugin, $app, [$controller, $action]);
static::$_callbacks[$key] = [$callback, $app, $controller, $action, null]; static::collectCallbacks($key, [$callback, $plugin, $app, $controller, $action, null]);
[$callback, $request->app, $request->controller, $request->action, $request->route] = static::$_callbacks[$key]; [$callback, $request->plugin, $request->app, $request->controller, $request->action, $request->route] = static::$_callbacks[$key];
static::send($connection, $callback($request), $request); static::send($connection, $callback($request), $request);
} catch (\Throwable $e) { } catch (Throwable $e) {
static::send($connection, static::exceptionResponse($e, $request), $request); static::send($connection, static::exceptionResponse($e, $request), $request);
} }
return null; return null;
} }
/** /**
* @param $path * @param $worker
* @return void
*/
public function onWorkerStart($worker)
{
static::$_worker = $worker;
Http::requestClass(static::$_requestClass);
}
/**
* @param string $key
* @param array $data
* @return void
*/
protected static function collectCallbacks(string $key, array $data)
{
static::$_callbacks[$key] = $data;
if (\count(static::$_callbacks) >= 1024) {
unset(static::$_callbacks[\key(static::$_callbacks)]);
}
}
/**
* @param TcpConnection $connection
* @param string $path
* @param $request
* @return bool * @return bool
*/ */
protected static function unsafeUri($path) protected static function unsafeUri(TcpConnection $connection, string $path, $request)
{ {
if (strpos($path, '/../') !== false || strpos($path,"\\") !== false || strpos($path, "\0") !== false) { if (\strpos($path, '..') !== false ||
\strpos($path, "\\") !== false ||
\strpos($path, "\0") !== false ||
\strpos($path, '//') !== false || !$path) {
$callback = static::getFallback(); $callback = static::getFallback();
$request->app = $request->controller = $request->action = ''; $request->app = $request->controller = $request->action = '';
static::send($connection, $callback($request), $request); static::send($connection, $callback($request), $request);
...@@ -184,9 +190,10 @@ class App ...@@ -184,9 +190,10 @@ class App
} }
/** /**
* @return \Closure * @return Closure
*/ */
protected static function getFallback() { protected static function getFallback()
{
// 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() ?: function () { return Route::getFallback() ?: function () {
return new Response(404, [], \file_get_contents(static::$_publicPath . '/404.html')); return new Response(404, [], \file_get_contents(static::$_publicPath . '/404.html'));
...@@ -194,28 +201,32 @@ class App ...@@ -194,28 +201,32 @@ class App
} }
/** /**
* @param \Throwable $e * @param Throwable $e
* @param $request * @param $request
* @return string|Response * @return string|Response
*/ */
protected static function exceptionResponse(\Throwable $e, $request) protected static function exceptionResponse(Throwable $e, $request)
{ {
try { try {
$app = $request->app ?: ''; $app = $request->app ?: '';
$exception_config = Config::get('exception'); $plugin = $request->plugin ?: '';
$exception_config = static::config($plugin, 'exception');
$default_exception = $exception_config[''] ?? ExceptionHandler::class; $default_exception = $exception_config[''] ?? ExceptionHandler::class;
$exception_handler_class = $exception_config[$app] ?? $default_exception; $exception_handler_class = $exception_config[$app] ?? $default_exception;
/** @var ExceptionHandlerInterface $exception_handler */ /** @var ExceptionHandlerInterface $exception_handler */
$exception_handler = static::$_container->make($exception_handler_class, [ $exception_handler = static::container($plugin)->make($exception_handler_class, [
'logger' => static::$_logger, 'logger' => static::$_logger,
'debug' => Config::get('app.debug') 'debug' => static::config($plugin, 'app.debug')
]); ]);
$exception_handler->report($e); $exception_handler->report($e);
$response = $exception_handler->render($request, $e); $response = $exception_handler->render($request, $e);
$response->exception($e);
return $response;
} catch (Throwable $e) {
$response = new Response(500, [], static::config($plugin, 'app.debug') ? (string)$e : $e->getMessage());
$response->exception($e);
return $response; return $response;
} catch (\Throwable $e) {
return Config::get('app.debug') ? (string)$e : $e->getMessage();
} }
} }
...@@ -225,37 +236,54 @@ class App ...@@ -225,37 +236,54 @@ class App
* @param null $args * @param null $args
* @param bool $with_global_middleware * @param bool $with_global_middleware
* @param RouteObject $route * @param RouteObject $route
* @return \Closure|mixed * @return callable
*/ */
protected static function getCallback($app, $call, $args = null, $with_global_middleware = true, $route = null) protected static function getCallback(string $plugin, string $app, $call, array $args = null, bool $with_global_middleware = true, RouteObject $route = null)
{ {
$args = $args === null ? null : \array_values($args); $args = $args === null ? null : \array_values($args);
$middlewares = []; $middlewares = [];
if ($route) { if ($route) {
$route_middlewares = \array_reverse($route->getMiddleware()); $route_middlewares = \array_reverse($route->getMiddleware());
foreach ($route_middlewares as $class_name) { foreach ($route_middlewares as $class_name) {
$middlewares[] = [App::container()->get($class_name), 'process']; $middlewares[] = [$class_name, 'process'];
}
}
$middlewares = \array_merge($middlewares, Middleware::getMiddleware($plugin, $app, $with_global_middleware));
foreach ($middlewares as $key => $item) {
$middlewares[$key][0] = static::container($plugin)->get($item[0]);
}
$controller_reuse = static::config($plugin, 'app.controller_reuse', true);
if (\is_array($call) && \is_string($call[0])) {
if (!$controller_reuse) {
$call = function ($request, ...$args) use ($call, $plugin) {
$call[0] = static::container($plugin)->make($call[0]);
return $call($request, ...$args);
};
} else {
$call[0] = static::container($plugin)->get($call[0]);
} }
} }
$middlewares = \array_merge($middlewares, Middleware::getMiddleware($app, $with_global_middleware));
if ($middlewares) { if ($middlewares) {
$callback = array_reduce($middlewares, function ($carry, $pipe) { $callback = \array_reduce($middlewares, function ($carry, $pipe) {
return function ($request) use ($carry, $pipe) { return function ($request) use ($carry, $pipe) {
return $pipe($request, $carry); return $pipe($request, $carry);
}; };
}, function ($request) use ($call, $args) { }, function ($request) use ($call, $args) {
try { try {
if ($args === null) { if ($args === null) {
$response = $call($request); $response = $call($request);
} else { } else {
$response = $call($request, ...$args); $response = $call($request, ...$args);
} }
} catch (\Throwable $e) { } catch (Throwable $e) {
return static::exceptionResponse($e, $request); return static::exceptionResponse($e, $request);
} }
if (\is_scalar($response) || null === $response) { if (!$response instanceof Response) {
if (\is_array($response)) {
$response = 'Array';
}
$response = new Response(200, [], $response); $response = new Response(200, [], $response);
} }
return $response; return $response;
...@@ -273,11 +301,12 @@ class App ...@@ -273,11 +301,12 @@ class App
} }
/** /**
* @param string $plugin
* @return ContainerInterface * @return ContainerInterface
*/ */
public static function container() public static function container(string $plugin = '')
{ {
return static::$_container; return static::config($plugin, 'container');
} }
/** /**
...@@ -305,91 +334,108 @@ class App ...@@ -305,91 +334,108 @@ class App
} }
/** /**
* @param $connection * @param TcpConnection $connection
* @param $path * @param string $path
* @param $key * @param string $key
* @param Request $request * @param Request $request
* @return bool * @return bool
*/ */
protected static function findRoute($connection, $path, $key, Request $request) protected static function findRoute(TcpConnection $connection, string $path, string $key, $request)
{ {
$ret = Route::dispatch($request->method(), $path); $ret = Route::dispatch($request->method(), $path);
if ($ret[0] === Dispatcher::FOUND) { if ($ret[0] === Dispatcher::FOUND) {
$ret[0] = 'route'; $ret[0] = 'route';
$callback = $ret[1]['callback']; $callback = $ret[1]['callback'];
$route = $ret[1]['route']; $route = clone $ret[1]['route'];
$app = $controller = $action = ''; $plugin = $app = $controller = $action = '';
$args = !empty($ret[2]) ? $ret[2] : null; $args = !empty($ret[2]) ? $ret[2] : null;
if (\is_array($callback) && isset($callback[0]) && $controller = \get_class($callback[0])) { if ($args) {
$route->setParams($args);
}
if (\is_array($callback)) {
$controller = $callback[0];
$plugin = static::getPluginByClass($controller);
$app = static::getAppByController($controller); $app = static::getAppByController($controller);
$action = static::getRealMethod($controller, $callback[1]) ?? ''; $action = static::getRealMethod($controller, $callback[1]) ?? '';
} }
$callback = static::getCallback($app, $callback, $args, true, $route); $callback = static::getCallback($plugin, $app, $callback, $args, true, $route);
static::$_callbacks[$key] = [$callback, $app, $controller ? $controller : '', $action, $route]; static::collectCallbacks($key, [$callback, $plugin, $app, $controller ?: '', $action, $route]);
[$callback, $request->app, $request->controller, $request->action, $request->route] = static::$_callbacks[$key]; [$callback, $request->plugin, $request->app, $request->controller, $request->action, $request->route] = static::$_callbacks[$key];
static::send($connection, $callback($request), $request); static::send($connection, $callback($request), $request);
if (\count(static::$_callbacks) > 1024) {
static::clearCache();
}
return true; return true;
} }
return false; return false;
} }
/** /**
* @param $connection * @param TcpConnection $connection
* @param $path * @param string $path
* @param $key * @param string $key
* @param $request * @param Request $request
* @return bool * @return bool
*/ */
protected static function findFile($connection, $path, $key, $request) protected static function findFile(TcpConnection $connection, string $path, string $key, $request)
{ {
$public_dir = static::$_publicPath; if (preg_match('/%[0-9a-f]{2}/i', $path)) {
$file = "$public_dir/$path"; $path = urldecode($path);
if (static::unsafeUri($connection, $path, $request)) {
return true;
}
}
$path_explodes = \explode('/', trim($path, '/'));
$plugin = '';
if (isset($path_explodes[1]) && $path_explodes[0] === 'app') {
$public_dir = BASE_PATH . "/plugin/{$path_explodes[1]}/public";
$plugin = $path_explodes[1];
$path = \substr($path, strlen("/app/{$path_explodes[1]}/"));
} else {
$public_dir = static::$_publicPath;
}
$file = "$public_dir/$path";
if (!\is_file($file)) { if (!\is_file($file)) {
return false; return false;
} }
if (\pathinfo($file, PATHINFO_EXTENSION) === 'php') { if (\pathinfo($file, PATHINFO_EXTENSION) === 'php') {
if (!static::$_supportPHPFiles) { if (!static::config($plugin, 'app.support_php_files', false)) {
return false; return false;
} }
static::$_callbacks[$key] = [function ($request) use ($file) { static::collectCallbacks($key, [function () use ($file) {
return static::execPhpFile($file); return static::execPhpFile($file);
}, '', '', '', null]; }, '', '', '', '', null]);
[$callback, $request->app, $request->controller, $request->action, $request->route] = static::$_callbacks[$key]; [, $request->plugin, $request->app, $request->controller, $request->action, $request->route] = static::$_callbacks[$key];
static::send($connection, static::execPhpFile($file), $request); static::send($connection, static::execPhpFile($file), $request);
return true; return true;
} }
if (!static::$_supportStaticFiles) { if (!static::config($plugin, 'static.enable', false)) {
return false; return false;
} }
static::$_callbacks[$key] = [static::getCallback('__static__', function ($request) use ($file) { static::collectCallbacks($key, [static::getCallback($plugin, '__static__', function ($request) use ($file) {
\clearstatcache(true, $file); \clearstatcache(true, $file);
if (!\is_file($file)) { if (!\is_file($file)) {
$callback = static::getFallback(); $callback = static::getFallback();
return $callback($request); return $callback($request);
} }
return (new Response())->file($file); return (new Response())->file($file);
}, null, false), '', '', '', null]; }, null, false), '', '', '', '', null]);
[$callback, $request->app, $request->controller, $request->action, $request->route] = static::$_callbacks[$key]; [$callback, $request->plugin, $request->app, $request->controller, $request->action, $request->route] = static::$_callbacks[$key];
static::send($connection, $callback($request), $request); static::send($connection, $callback($request), $request);
return true; return true;
} }
/** /**
* @param TcpConnection $connection * @param TcpConnection $connection
* @param $response * @param Response $response
* @param Request $request * @param Request $request
* @return void
*/ */
protected static function send(TcpConnection $connection, $response, Request $request) protected static function send(TcpConnection $connection, $response, $request)
{ {
$keep_alive = $request->header('connection'); $keep_alive = $request->header('connection');
static::$_request = static::$_connection = null;
if (($keep_alive === null && $request->protocolVersion() === '1.1') if (($keep_alive === null && $request->protocolVersion() === '1.1')
|| $keep_alive === 'keep-alive' || $keep_alive === 'Keep-Alive' || $keep_alive === 'keep-alive' || $keep_alive === 'Keep-Alive'
) { ) {
...@@ -400,112 +446,111 @@ class App ...@@ -400,112 +446,111 @@ class App
} }
/** /**
* @param $path * @param string $path
* @return array|bool * @return array|false
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
* @throws \ReflectionException
*/ */
protected static function parseControllerAction($path) protected static function parseControllerAction(string $path)
{ {
$suffix = config('app.controller_suffix', ''); $path_explode = \explode('/', trim($path, '/'));
$app = ''; $is_plugin = isset($path_explode[1]) && $path_explode[0] === 'app';
if ($path === '/' || $path === '') { $config_prefix = $is_plugin ? "plugin.{$path_explode[1]}." : '';
$controller_class = 'app\controller\Index' . $suffix; $path_prefix = $is_plugin ? "/app/{$path_explode[1]}" : '';
$action = 'index'; $class_prefix = $is_plugin ? "plugin\\{$path_explode[1]}" : '';
if ($controller_action = static::getControllerAction($controller_class, $action)) { $suffix = Config::get("{$config_prefix}app.controller_suffix", '');
return $controller_action; $relative_path = \trim(substr($path, strlen($path_prefix)), '/');
} $path_explode = $relative_path ? \explode('/', $relative_path) : [];
$controller_class = 'app\index\controller\Index' . $suffix;
if ($controller_action = static::getControllerAction($controller_class, $action)) {
return $controller_action;
}
return false;
}
if ($path && $path[0] === '/') {
$path = \substr($path, 1);
}
$explode = \explode('/', $path);
$action = 'index';
$controller = $explode[0]; $action = 'index';
if ($controller === '') { if ($controller_action = static::guessControllerAction($path_explode, $action, $suffix, $class_prefix)) {
return false;
}
if (!empty($explode[1])) {
$action = $explode[1];
}
$controller_class = "app\\controller\\$controller$suffix";
if ($controller_action = static::getControllerAction($controller_class, $action)) {
return $controller_action; return $controller_action;
} }
$action = \end($path_explode);
unset($path_explode[count($path_explode) - 1]);
return static::guessControllerAction($path_explode, $action, $suffix, $class_prefix);
}
$app = $explode[0]; /**
$controller = $action = 'index'; * @param $path_explode
if (!empty($explode[1])) { * @param $action
$controller = $explode[1]; * @param $suffix
if (!empty($explode[2])) { * @return array|false
$action = $explode[2]; * @throws \ReflectionException
} */
protected static function guessControllerAction($path_explode, $action, $suffix, $class_prefix)
{
$map[] = "$class_prefix\\app\\controller\\" . \implode('\\', $path_explode);
foreach ($path_explode as $index => $section) {
$tmp = $path_explode;
\array_splice($tmp, $index, 1, [$section, 'controller']);
$map[] = "$class_prefix\\" . \implode('\\', \array_merge(['app'], $tmp));
} }
$controller_class = "app\\$app\\controller\\$controller$suffix"; $last_index = \count($map) - 1;
if ($controller_action = static::getControllerAction($controller_class, $action)) { $map[$last_index] = \trim($map[$last_index], '\\') . '\\index';
return $controller_action; foreach ($map as $controller_class) {
$controller_class .= $suffix;
if ($controller_action = static::getControllerAction($controller_class, $action)) {
return $controller_action;
}
} }
return false; return false;
} }
/** /**
* @param $controller_class * @param string $controller_class
* @param $action * @param string $action
* @return array|false * @return array|false
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
* @throws \ReflectionException * @throws \ReflectionException
*/ */
protected static function getControllerAction($controller_class, $action) protected static function getControllerAction(string $controller_class, string $action)
{ {
if (static::loadController($controller_class) && ($controller_class = (new \ReflectionClass($controller_class))->name) && \is_callable([$instance = static::$_container->get($controller_class), $action])) { if (static::loadController($controller_class) && ($controller_class = (new \ReflectionClass($controller_class))->name) && \method_exists($controller_class, $action)) {
return [ return [
'app' => static::getAppByController($controller_class), 'plugin' => static::getPluginByClass($controller_class),
'app' => static::getAppByController($controller_class),
'controller' => $controller_class, 'controller' => $controller_class,
'action' => static::getRealMethod($controller_class, $action), 'action' => static::getRealMethod($controller_class, $action)
'instance' => $instance,
]; ];
} }
return false; return false;
} }
/** /**
* @param $controller_class * @param string $controller_class
* @return bool * @return bool
*/ */
protected static function loadController($controller_class) protected static function loadController(string $controller_class)
{ {
static $controller_files = [];
if (empty($controller_files)) {
$app_path = static::$_appPath;
$dir_iterator = new \RecursiveDirectoryIterator($app_path);
$iterator = new \RecursiveIteratorIterator($dir_iterator);
$app_base_path_length = \strrpos($app_path, DIRECTORY_SEPARATOR) + 1;
foreach ($iterator as $spl_file) {
$file = (string)$spl_file;
if (\is_dir($file) || false === \strpos(strtolower($file), '/controller/') || $spl_file->getExtension() !== 'php') {
continue;
}
$controller_files[$file] = \str_replace(DIRECTORY_SEPARATOR, "\\", \strtolower(\substr(\substr($file, $app_base_path_length), 0, -4)));
}
}
if (\class_exists($controller_class)) { if (\class_exists($controller_class)) {
return true; return true;
} }
$explodes = \explode('\\', strtolower(ltrim($controller_class, '\\')));
$controller_class = \strtolower($controller_class); $base_path = $explodes[0] === 'plugin' ? BASE_PATH . '/plugin' : static::$_appPath;
if ($controller_class[0] === "\\") { unset($explodes[0]);
$controller_class = \substr($controller_class, 1); $file_name = \array_pop($explodes) . '.php';
$finded = true;
foreach ($explodes as $path_section) {
if (!$finded) {
break;
}
$dirs = Util::scanDir($base_path, false);
$finded = false;
foreach ($dirs as $name) {
if (\strtolower($name) === $path_section) {
$base_path = "$base_path/$name";
$finded = true;
break;
}
}
} }
foreach ($controller_files as $real_path => $class_name) { if (!$finded) {
if ($class_name === $controller_class) { return false;
require_once $real_path; }
foreach (\scandir($base_path) ?: [] as $name) {
if (\strtolower($name) === $file_name) {
require_once "$base_path/$name";
if (\class_exists($controller_class, false)) { if (\class_exists($controller_class, false)) {
return true; return true;
} }
...@@ -515,26 +560,39 @@ class App ...@@ -515,26 +560,39 @@ class App
} }
/** /**
* @param $controller_calss * @param string $controller_class
* @return string * @return mixed|string
*/ */
protected static function getAppByController($controller_calss) public static function getPluginByClass(string $controller_class)
{ {
if ($controller_calss[0] === '\\') { $controller_class = \trim($controller_class, '\\');
$controller_calss = \substr($controller_calss, 1); $tmp = \explode('\\', $controller_class, 3);
if ($tmp[0] !== 'plugin') {
return '';
} }
$tmp = \explode('\\', $controller_calss, 3); return $tmp[1] ?? '';
if (!isset($tmp[1])) { }
/**
* @param string $controller_class
* @return mixed|string
*/
protected static function getAppByController(string $controller_class)
{
$controller_class = \trim($controller_class, '\\');
$tmp = \explode('\\', $controller_class, 5);
$pos = $tmp[0] === 'plugin' ? 3 : 1;
if (!isset($tmp[$pos])) {
return ''; return '';
} }
return strtolower($tmp[1]) === 'controller' ? '' : $tmp[1]; return \strtolower($tmp[$pos]) === 'controller' ? '' : $tmp[$pos];
} }
/** /**
* @param $file * @param string $file
* @return string * @return false|string
*/ */
public static function execPhpFile($file) public static function execPhpFile(string $file)
{ {
\ob_start(); \ob_start();
// Try to include php file. // Try to include php file.
...@@ -547,19 +605,11 @@ class App ...@@ -547,19 +605,11 @@ class App
} }
/** /**
* Clear cache. * @param string $class
*/ * @param string $method
public static function clearCache()
{
static::$_callbacks = [];
}
/**
* @param $class
* @param $method
* @return string * @return string
*/ */
protected static function getRealMethod($class, $method) protected static function getRealMethod(string $class, string $method)
{ {
$method = \strtolower($method); $method = \strtolower($method);
$methods = \get_class_methods($class); $methods = \get_class_methods($class);
...@@ -571,4 +621,15 @@ class App ...@@ -571,4 +621,15 @@ class App
return $method; return $method;
} }
/**
* @param string $plugin
* @param string $key
* @param $default
* @return array|mixed|null
*/
protected static function config(string $plugin, string $key, $default = null)
{
return Config::get($plugin ? "plugin.$plugin.$key" : $key, $default);
}
} }
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
* @link http://www.workerman.net/ * @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License * @license http://www.opensource.org/licenses/mit-license.php MIT License
*/ */
namespace Webman; namespace Webman;
use Workerman\Worker; use Workerman\Worker;
......
...@@ -33,83 +33,169 @@ class Config ...@@ -33,83 +33,169 @@ class Config
protected static $_loaded = false; protected static $_loaded = false;
/** /**
* @param $config_path * @param string $config_path
* @param array $exclude_file * @param array $exclude_file
* @param string|null $key
* @return void
*/ */
public static function load($config_path, $exclude_file = []) public static function load(string $config_path, array $exclude_file = [], string $key = null)
{ {
static::$_configPath = $config_path; static::$_configPath = $config_path;
if (!$config_path) { if (!$config_path) {
return; return;
} }
$dir_iterator = new \RecursiveDirectoryIterator($config_path, \FilesystemIterator::FOLLOW_SYMLINKS); static::$_loaded = false;
$iterator = new \RecursiveIteratorIterator($dir_iterator); $config = static::loadFromDir($config_path, $exclude_file);
foreach ($iterator as $file) { if (!$config) {
/** var SplFileInfo $file */ static::$_loaded = true;
if (is_dir($file) || $file->getExtension() != 'php' || \in_array($file->getBaseName('.php'), $exclude_file)) { return;
continue; }
if ($key !== null) {
foreach (\array_reverse(\explode('.', $key)) as $k) {
$config = [$k => $config];
} }
$app_config_file = $file->getPath() . '/app.php'; }
if (!is_file($app_config_file)) { static::$_config = \array_replace_recursive(static::$_config, $config);
continue; static::formatConfig();
static::$_loaded = true;
}
/**
* This deprecated method will certainly be removed in the future
*
* @deprecated
* @param string $config_path
* @param array $exclude_file
* @return void
*/
public static function reload(string $config_path, array $exclude_file = [])
{
static::load($config_path, $exclude_file);
}
/**
* @return void
*/
protected static function formatConfig()
{
$config = static::$_config;
// Merge log config
foreach ($config['plugin'] ?? [] as $firm => $projects) {
if (isset($projects['app'])) {
foreach ($projects['log'] ?? [] as $key => $item) {
$config['log']["plugin.$firm.$key"] = $item;
}
} }
$relative_path = str_replace($config_path . DIRECTORY_SEPARATOR, '', substr($file, 0, -4)); foreach ($projects as $name => $project) {
$explode = array_reverse(explode(DIRECTORY_SEPARATOR, $relative_path)); if (!\is_array($project)) {
if (count($explode) >= 2) {
$app_config = include $app_config_file;
if (empty($app_config['enable'])) {
continue; continue;
} }
foreach ($project['log'] ?? [] as $key => $item) {
$config['log']["plugin.$firm.$name.$key"] = $item;
}
} }
$config = include $file;
foreach ($explode as $section) {
$tmp = [];
$tmp[$section] = $config;
$config = $tmp;
}
static::$_config = array_replace_recursive(static::$_config, $config);
} }
// Merge database config // Merge database config
foreach (static::$_config['plugin'] ?? [] as $firm => $projects) { foreach ($config['plugin'] ?? [] as $firm => $projects) {
if (isset($projects['app'])) {
foreach ($projects['database']['connections'] ?? [] as $key => $connection) {
$config['database']['connections']["plugin.$firm.$key"] = $connection;
}
}
foreach ($projects as $name => $project) { foreach ($projects as $name => $project) {
if (!\is_array($project)) {
continue;
}
foreach ($project['database']['connections'] ?? [] as $key => $connection) { foreach ($project['database']['connections'] ?? [] as $key => $connection) {
static::$_config['database']['connections']["plugin.$firm.$name.$key"] = $connection; $config['database']['connections']["plugin.$firm.$name.$key"] = $connection;
} }
} }
} }
if (!empty(static::$_config['database']['connections'])) { if (!empty($config['database']['connections'])) {
static::$_config['database']['default'] = static::$_config['database']['default'] ?? key(static::$_config['database']['connections']); $config['database']['default'] = $config['database']['default'] ?? key($config['database']['connections']);
} }
// Merge thinkorm config // Merge thinkorm config
foreach (static::$_config['plugin'] ?? [] as $firm => $projects) { foreach ($config['plugin'] ?? [] as $firm => $projects) {
if (isset($projects['app'])) {
foreach ($projects['thinkorm']['connections'] ?? [] as $key => $connection) {
$config['thinkorm']['connections']["plugin.$firm.$key"] = $connection;
}
}
foreach ($projects as $name => $project) { foreach ($projects as $name => $project) {
if (!\is_array($project)) {
continue;
}
foreach ($project['thinkorm']['connections'] ?? [] as $key => $connection) { foreach ($project['thinkorm']['connections'] ?? [] as $key => $connection) {
static::$_config['thinkorm']['connections']["plugin.$firm.$name.$key"] = $connection; $config['thinkorm']['connections']["plugin.$firm.$name.$key"] = $connection;
} }
} }
} }
if (!empty(static::$_config['thinkorm']['connections'])) { if (!empty($config['thinkorm']['connections'])) {
static::$_config['thinkorm']['default'] = static::$_config['thinkorm']['default'] ?? key(static::$_config['thinkorm']['connections']); $config['thinkorm']['default'] = $config['thinkorm']['default'] ?? \key($config['thinkorm']['connections']);
} }
// Merge redis config // Merge redis config
foreach (static::$_config['plugin'] ?? [] as $firm => $projects) { foreach ($config['plugin'] ?? [] as $firm => $projects) {
if (isset($projects['app'])) {
foreach ($projects['redis'] ?? [] as $key => $connection) {
$config['redis']["plugin.$firm.$key"] = $connection;
}
}
foreach ($projects as $name => $project) { foreach ($projects as $name => $project) {
if (!\is_array($project)) {
continue;
}
foreach ($project['redis'] ?? [] as $key => $connection) { foreach ($project['redis'] ?? [] as $key => $connection) {
static::$_config['redis']["plugin.$firm.$name.$key"] = $connection; $config['redis']["plugin.$firm.$name.$key"] = $connection;
} }
} }
} }
static::$_config = $config;
}
static::$_loaded = true; /**
* @param string $config_path
* @param array $exclude_file
* @return array
*/
public static function loadFromDir(string $config_path, array $exclude_file = [])
{
$all_config = [];
$dir_iterator = new \RecursiveDirectoryIterator($config_path, \FilesystemIterator::FOLLOW_SYMLINKS);
$iterator = new \RecursiveIteratorIterator($dir_iterator);
foreach ($iterator as $file) {
/** var SplFileInfo $file */
if (\is_dir($file) || $file->getExtension() != 'php' || \in_array($file->getBaseName('.php'), $exclude_file)) {
continue;
}
$app_config_file = $file->getPath() . '/app.php';
if (!\is_file($app_config_file)) {
continue;
}
$relative_path = \str_replace($config_path . DIRECTORY_SEPARATOR, '', substr($file, 0, -4));
$explode = \array_reverse(\explode(DIRECTORY_SEPARATOR, $relative_path));
if (\count($explode) >= 2) {
$app_config = include $app_config_file;
if (empty($app_config['enable'])) {
continue;
}
}
$config = include $file;
foreach ($explode as $section) {
$tmp = [];
$tmp[$section] = $config;
$config = $tmp;
}
$all_config = \array_replace_recursive($all_config, $config);
}
return $all_config;
} }
/** /**
* @param null $key * @param string|null $key
* @param null $default * @param mixed $default
* @return array|mixed|null * @return array|mixed|void|null
*/ */
public static function get($key = null, $default = null) public static function get(string $key = null, $default = null)
{ {
if ($key === null) { if ($key === null) {
return static::$_config; return static::$_config;
...@@ -134,11 +220,11 @@ class Config ...@@ -134,11 +220,11 @@ class Config
} }
/** /**
* @param $key * @param string $key
* @param $default * @param mixed $default
* @return array|mixed|void|null * @return array|mixed|null
*/ */
protected static function read($key, $default = null) protected static function read(string $key, $default = null)
{ {
$path = static::$_configPath; $path = static::$_configPath;
if ($path === '') { if ($path === '') {
...@@ -147,11 +233,11 @@ class Config ...@@ -147,11 +233,11 @@ class Config
$keys = $key_array = \explode('.', $key); $keys = $key_array = \explode('.', $key);
foreach ($key_array as $index => $section) { foreach ($key_array as $index => $section) {
unset($keys[$index]); unset($keys[$index]);
if (is_file($file = "$path/$section.php")) { if (\is_file($file = "$path/$section.php")) {
$config = include $file; $config = include $file;
return static::find($keys, $config, $default); return static::find($keys, $config, $default);
} }
if (!is_dir($path = "$path/$section")) { if (!\is_dir($path = "$path/$section")) {
return $default; return $default;
} }
} }
...@@ -159,14 +245,14 @@ class Config ...@@ -159,14 +245,14 @@ class Config
} }
/** /**
* @param $key_array * @param array $key_array
* @param $stack * @param mixed $stack
* @param $default * @param mixed $default
* @return array|mixed * @return array|mixed
*/ */
protected static function find($key_array, $stack, $default) protected static function find(array $key_array, $stack, $default)
{ {
if (!is_array($stack)) { if (!\is_array($stack)) {
return $default; return $default;
} }
$value = $stack; $value = $stack;
...@@ -179,15 +265,4 @@ class Config ...@@ -179,15 +265,4 @@ class Config
return $value; return $value;
} }
/**
* @param $config_path
* @param array $exclude_file
*/
public static function reload($config_path, $exclude_file = [])
{
static::$_config = [];
static::load($config_path, $exclude_file);
}
} }
<?php <?php
namespace Webman; namespace Webman;
use Psr\Container\ContainerInterface; use Psr\Container\ContainerInterface;
...@@ -21,10 +22,10 @@ class Container implements ContainerInterface ...@@ -21,10 +22,10 @@ class Container implements ContainerInterface
* @return mixed * @return mixed
* @throws NotFoundException * @throws NotFoundException
*/ */
public function get($name) public function get(string $name)
{ {
if (!isset($this->_instances[$name])) { if (!isset($this->_instances[$name])) {
if (!class_exists($name)) { if (!\class_exists($name)) {
throw new NotFoundException("Class '$name' not found"); throw new NotFoundException("Class '$name' not found");
} }
$this->_instances[$name] = new $name(); $this->_instances[$name] = new $name();
...@@ -36,20 +37,20 @@ class Container implements ContainerInterface ...@@ -36,20 +37,20 @@ class Container implements ContainerInterface
* @param string $name * @param string $name
* @return bool * @return bool
*/ */
public function has($name): bool public function has(string $name): bool
{ {
return \array_key_exists($name, $this->_instances); return \array_key_exists($name, $this->_instances);
} }
/** /**
* @param $name * @param string $name
* @param array $constructor * @param array $constructor
* @return mixed * @return mixed
* @throws NotFoundException * @throws NotFoundException
*/ */
public function make($name, array $constructor = []) public function make(string $name, array $constructor = [])
{ {
if (!class_exists($name)) { if (!\class_exists($name)) {
throw new NotFoundException("Class '$name' not found"); throw new NotFoundException("Class '$name' not found");
} }
return new $name(... array_values($constructor)); return new $name(... array_values($constructor));
......
...@@ -11,16 +11,17 @@ ...@@ -11,16 +11,17 @@
* @link http://www.workerman.net/ * @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License * @license http://www.opensource.org/licenses/mit-license.php MIT License
*/ */
namespace Webman\Exception; namespace Webman\Exception;
use Throwable;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Throwable;
use Webman\Http\Request; use Webman\Http\Request;
use Webman\Http\Response; use Webman\Http\Response;
/** /**
* Class Handler * Class Handler
* @package support\exception * @package Support\Exception
*/ */
class ExceptionHandler implements ExceptionHandlerInterface class ExceptionHandler implements ExceptionHandlerInterface
{ {
...@@ -37,9 +38,7 @@ class ExceptionHandler implements ExceptionHandlerInterface ...@@ -37,9 +38,7 @@ class ExceptionHandler implements ExceptionHandlerInterface
/** /**
* @var array * @var array
*/ */
public $dontReport = [ public $dontReport = [];
];
/** /**
* ExceptionHandler constructor. * ExceptionHandler constructor.
...@@ -61,8 +60,11 @@ class ExceptionHandler implements ExceptionHandlerInterface ...@@ -61,8 +60,11 @@ class ExceptionHandler implements ExceptionHandlerInterface
if ($this->shouldntReport($exception)) { if ($this->shouldntReport($exception)) {
return; return;
} }
$logs = '';
$this->_logger->error($exception->getMessage(), ['exception' => (string)$exception]); if ($request = \request()) {
$logs = $request->getRealIp() . ' ' . $request->method() . ' ' . \trim($request->fullUrl(), '/');
}
$this->_logger->error($logs . PHP_EOL . $exception);
} }
/** /**
...@@ -70,16 +72,16 @@ class ExceptionHandler implements ExceptionHandlerInterface ...@@ -70,16 +72,16 @@ class ExceptionHandler implements ExceptionHandlerInterface
* @param Throwable $exception * @param Throwable $exception
* @return Response * @return Response
*/ */
public function render(Request $request, Throwable $exception) : Response public function render(Request $request, Throwable $exception): Response
{ {
$code = $exception->getCode(); $code = $exception->getCode();
if ($request->expectsJson()) { if ($request->expectsJson()) {
$json = ['code' => $code ? $code : 500, 'msg' => $exception->getMessage()]; $json = ['code' => $code ? $code : 500, 'msg' => $this->_debug ? $exception->getMessage() : 'Server internal error'];
$this->_debug && $json['traces'] = (string)$exception; $this->_debug && $json['traces'] = (string)$exception;
return new Response(200, ['Content-Type' => 'application/json'], return new Response(200, ['Content-Type' => 'application/json'],
json_encode($json, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); \json_encode($json, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
} }
$error = $this->_debug ? nl2br((string)$exception) : 'Server internal error'; $error = $this->_debug ? \nl2br((string)$exception) : 'Server internal error';
return new Response(500, [], $error); return new Response(500, [], $error);
} }
...@@ -87,7 +89,8 @@ class ExceptionHandler implements ExceptionHandlerInterface ...@@ -87,7 +89,8 @@ class ExceptionHandler implements ExceptionHandlerInterface
* @param Throwable $e * @param Throwable $e
* @return bool * @return bool
*/ */
protected function shouldntReport(Throwable $e) { protected function shouldntReport(Throwable $e)
{
foreach ($this->dontReport as $type) { foreach ($this->dontReport as $type) {
if ($e instanceof $type) { if ($e instanceof $type) {
return true; return true;
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
* @link http://www.workerman.net/ * @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License * @license http://www.opensource.org/licenses/mit-license.php MIT License
*/ */
namespace Webman\Exception; namespace Webman\Exception;
use Throwable; use Throwable;
...@@ -30,5 +31,5 @@ interface ExceptionHandlerInterface ...@@ -30,5 +31,5 @@ interface ExceptionHandlerInterface
* @param Throwable $e * @param Throwable $e
* @return Response * @return Response
*/ */
public function render(Request $request, Throwable $e) : Response; public function render(Request $request, Throwable $e): Response;
} }
\ No newline at end of file
...@@ -11,12 +11,15 @@ ...@@ -11,12 +11,15 @@
* @link http://www.workerman.net/ * @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License * @license http://www.opensource.org/licenses/mit-license.php MIT License
*/ */
namespace Webman\Exception; namespace Webman\Exception;
use RuntimeException;
/** /**
* Class FileException * Class FileException
* @package Webman\Exception * @package Webman\Exception
*/ */
class FileException extends \RuntimeException class FileException extends RuntimeException
{ {
} }
\ No newline at end of file
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
* @link http://www.workerman.net/ * @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License * @license http://www.opensource.org/licenses/mit-license.php MIT License
*/ */
namespace Webman; namespace Webman;
use Webman\Exception\FileException; use Webman\Exception\FileException;
...@@ -19,25 +20,25 @@ class File extends \SplFileInfo ...@@ -19,25 +20,25 @@ class File extends \SplFileInfo
{ {
/** /**
* @param $destination * @param string $destination
* @return File * @return File
*/ */
public function move($destination) public function move(string $destination)
{ {
set_error_handler(function ($type, $msg) use (&$error) { \set_error_handler(function ($type, $msg) use (&$error) {
$error = $msg; $error = $msg;
}); });
$path = pathinfo($destination, PATHINFO_DIRNAME); $path = \pathinfo($destination, PATHINFO_DIRNAME);
if (!is_dir($path) && !mkdir($path, 0777, true)) { if (!\is_dir($path) && !\mkdir($path, 0777, true)) {
restore_error_handler(); \restore_error_handler();
throw new FileException(sprintf('Unable to create the "%s" directory (%s)', $path, strip_tags($error))); throw new FileException(\sprintf('Unable to create the "%s" directory (%s)', $path, \strip_tags($error)));
} }
if (!rename($this->getPathname(), $destination)) { if (!rename($this->getPathname(), $destination)) {
restore_error_handler(); \restore_error_handler();
throw new FileException(sprintf('Could not move the file "%s" to "%s" (%s)', $this->getPathname(), $destination, strip_tags($error))); throw new FileException(\sprintf('Could not move the file "%s" to "%s" (%s)', $this->getPathname(), $destination, \strip_tags($error)));
} }
restore_error_handler(); \restore_error_handler();
@chmod($destination, 0666 & ~umask()); @\chmod($destination, 0666 & ~\umask());
return new self($destination); return new self($destination);
} }
......
...@@ -13,15 +13,13 @@ ...@@ -13,15 +13,13 @@
*/ */
namespace Webman; namespace Webman;
use FastRoute\Dispatcher\GroupCountBased;
use FastRoute\RouteCollector;
use Workerman\Protocols\Http\Session\FileSessionHandler as SessionHandler;
/** /**
* Class FileSessionHandler * This deprecated class will certainly be removed in the future.
* Please use Webman\Session\FileSessionHandler
* @deprecated
* @package Webman * @package Webman
*/ */
class FileSessionHandler extends SessionHandler class FileSessionHandler extends Session\FileSessionHandler
{ {
} }
...@@ -11,11 +11,11 @@ ...@@ -11,11 +11,11 @@
* @link http://www.workerman.net/ * @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License * @license http://www.opensource.org/licenses/mit-license.php MIT License
*/ */
namespace Webman\Http; namespace Webman\Http;
use Webman\App; use Webman\App;
use Webman\Route\Route; use Webman\Route\Route;
use Webman\Http\UploadFile;
/** /**
* Class Request * Class Request
...@@ -23,6 +23,11 @@ use Webman\Http\UploadFile; ...@@ -23,6 +23,11 @@ use Webman\Http\UploadFile;
*/ */
class Request extends \Workerman\Protocols\Http\Request class Request extends \Workerman\Protocols\Http\Request
{ {
/**
* @var string
*/
public $plugin = null;
/** /**
* @var string * @var string
*/ */
...@@ -97,7 +102,7 @@ class Request extends \Workerman\Protocols\Http\Request ...@@ -97,7 +102,7 @@ class Request extends \Workerman\Protocols\Http\Request
/** /**
* @param string|null $name * @param string|null $name
* @return null|array|UploadFile * @return null|UploadFile[]|UploadFile
*/ */
public function file($name = null) public function file($name = null)
{ {
...@@ -125,10 +130,10 @@ class Request extends \Workerman\Protocols\Http\Request ...@@ -125,10 +130,10 @@ class Request extends \Workerman\Protocols\Http\Request
} }
/** /**
* @param $file * @param array $file
* @return UploadFile * @return UploadFile
*/ */
protected function parseFile($file) protected function parseFile(array $file)
{ {
return new UploadFile($file['tmp_name'], $file['name'], $file['type'], $file['error']); return new UploadFile($file['tmp_name'], $file['name'], $file['type'], $file['error']);
} }
...@@ -137,7 +142,7 @@ class Request extends \Workerman\Protocols\Http\Request ...@@ -137,7 +142,7 @@ class Request extends \Workerman\Protocols\Http\Request
* @param array $files * @param array $files
* @return array * @return array
*/ */
protected function parseFiles($files) protected function parseFiles(array $files)
{ {
$upload_files = []; $upload_files = [];
foreach ($files as $key => $file) { foreach ($files as $key => $file) {
...@@ -186,15 +191,15 @@ class Request extends \Workerman\Protocols\Http\Request ...@@ -186,15 +191,15 @@ class Request extends \Workerman\Protocols\Http\Request
* @param bool $safe_mode * @param bool $safe_mode
* @return string * @return string
*/ */
public function getRealIp($safe_mode = true) public function getRealIp(bool $safe_mode = true)
{ {
$remote_ip = $this->getRemoteIp(); $remote_ip = $this->getRemoteIp();
if ($safe_mode && !static::isIntranetIp($remote_ip)) { if ($safe_mode && !static::isIntranetIp($remote_ip)) {
return $remote_ip; return $remote_ip;
} }
return $this->header('client-ip', $this->header('x-forwarded-for', return $this->header('client-ip', $this->header('x-forwarded-for',
$this->header('x-real-ip', $this->header('x-client-ip', $this->header('x-real-ip', $this->header('x-client-ip',
$this->header('via', $remote_ip))))); $this->header('via', $remote_ip)))));
} }
/** /**
...@@ -242,25 +247,25 @@ class Request extends \Workerman\Protocols\Http\Request ...@@ -242,25 +247,25 @@ class Request extends \Workerman\Protocols\Http\Request
*/ */
public function acceptJson() public function acceptJson()
{ {
return false !== strpos($this->header('accept', ''), 'json'); return false !== \strpos($this->header('accept', ''), 'json');
} }
/** /**
* @param string $ip * @param string $ip
* @return bool * @return bool
*/ */
public static function isIntranetIp($ip) public static function isIntranetIp(string $ip)
{ {
// Not validate ip . // Not validate ip .
if (!filter_var($ip, FILTER_VALIDATE_IP)) { if (!\filter_var($ip, \FILTER_VALIDATE_IP)) {
return false; return false;
} }
// Is intranet ip ? For IPv4, the result of false may not be accurate, so we need to check it manually later . // Is intranet ip ? For IPv4, the result of false may not be accurate, so we need to check it manually later .
if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) { if (!\filter_var($ip, \FILTER_VALIDATE_IP, \FILTER_FLAG_NO_PRIV_RANGE | \FILTER_FLAG_NO_RES_RANGE)) {
return true; return true;
} }
// Manual check only for IPv4 . // Manual check only for IPv4 .
if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { if (!\filter_var($ip, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV4)) {
return false; return false;
} }
// Manual check . // Manual check .
...@@ -274,7 +279,7 @@ class Request extends \Workerman\Protocols\Http\Request ...@@ -274,7 +279,7 @@ class Request extends \Workerman\Protocols\Http\Request
3405803776 => 3405804031, // 203.0.113.0 - 203.0.113.255 3405803776 => 3405804031, // 203.0.113.0 - 203.0.113.255
3758096384 => 4026531839, // 224.0.0.0 - 239.255.255.255 3758096384 => 4026531839, // 224.0.0.0 - 239.255.255.255
]; ];
$ip_long = ip2long($ip); $ip_long = \ip2long($ip);
foreach ($reserved_ips as $ip_start => $ip_end) { foreach ($reserved_ips as $ip_start => $ip_end) {
if (($ip_long >= $ip_start) && ($ip_long <= $ip_end)) { if (($ip_long >= $ip_start) && ($ip_long <= $ip_end)) {
return true; return true;
...@@ -282,5 +287,5 @@ class Request extends \Workerman\Protocols\Http\Request ...@@ -282,5 +287,5 @@ class Request extends \Workerman\Protocols\Http\Request
} }
return false; return false;
} }
} }
...@@ -11,9 +11,11 @@ ...@@ -11,9 +11,11 @@
* @link http://www.workerman.net/ * @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License * @license http://www.opensource.org/licenses/mit-license.php MIT License
*/ */
namespace Webman\Http; namespace Webman\Http;
use Webman\App; use Webman\App;
use Throwable;
/** /**
* Class Response * Class Response
...@@ -21,11 +23,16 @@ use Webman\App; ...@@ -21,11 +23,16 @@ use Webman\App;
*/ */
class Response extends \Workerman\Protocols\Http\Response class Response extends \Workerman\Protocols\Http\Response
{ {
/**
* @var Throwable
*/
protected $_exception = null;
/** /**
* @param string $file * @param string $file
* @return $this * @return $this
*/ */
public function file($file) public function file(string $file)
{ {
if ($this->notModifiedSince($file)) { if ($this->notModifiedSince($file)) {
return $this->withStatus(304); return $this->withStatus(304);
...@@ -38,7 +45,7 @@ class Response extends \Workerman\Protocols\Http\Response ...@@ -38,7 +45,7 @@ class Response extends \Workerman\Protocols\Http\Response
* @param string $download_name * @param string $download_name
* @return $this * @return $this
*/ */
public function download($file, $download_name = '') public function download(string $file, string $download_name = '')
{ {
$this->withFile($file); $this->withFile($file);
if ($download_name) { if ($download_name) {
...@@ -48,10 +55,10 @@ class Response extends \Workerman\Protocols\Http\Response ...@@ -48,10 +55,10 @@ class Response extends \Workerman\Protocols\Http\Response
} }
/** /**
* @param $file * @param string $file
* @return bool * @return bool
*/ */
protected function notModifiedSince($file) protected function notModifiedSince(string $file)
{ {
$if_modified_since = App::request()->header('if-modified-since'); $if_modified_since = App::request()->header('if-modified-since');
if ($if_modified_since === null || !($mtime = \filemtime($file))) { if ($if_modified_since === null || !($mtime = \filemtime($file))) {
...@@ -59,4 +66,16 @@ class Response extends \Workerman\Protocols\Http\Response ...@@ -59,4 +66,16 @@ class Response extends \Workerman\Protocols\Http\Response
} }
return $if_modified_since === \gmdate('D, d M Y H:i:s', $mtime) . ' GMT'; return $if_modified_since === \gmdate('D, d M Y H:i:s', $mtime) . ' GMT';
} }
/**
* @param Throwable $exception
* @return Throwable
*/
public function exception($exception = null)
{
if ($exception) {
$this->_exception = $exception;
}
return $this->_exception;
}
} }
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
* @link http://www.workerman.net/ * @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License * @license http://www.opensource.org/licenses/mit-license.php MIT License
*/ */
namespace Webman\Http; namespace Webman\Http;
use Webman\File; use Webman\File;
...@@ -38,12 +39,13 @@ class UploadFile extends File ...@@ -38,12 +39,13 @@ class UploadFile extends File
/** /**
* UploadFile constructor. * UploadFile constructor.
* @param $file_name *
* @param $upload_name * @param string $file_name
* @param $upload_mime_type * @param string $upload_name
* @param $upload_error_code * @param string $upload_mime_type
* @param int $upload_error_code
*/ */
public function __construct($file_name, $upload_name, $upload_mime_type, $upload_error_code) public function __construct(string $file_name, string $upload_name, string $upload_mime_type, int $upload_error_code)
{ {
$this->_uploadName = $upload_name; $this->_uploadName = $upload_name;
$this->_uploadMimeType = $upload_mime_type; $this->_uploadMimeType = $upload_mime_type;
...@@ -72,7 +74,7 @@ class UploadFile extends File ...@@ -72,7 +74,7 @@ class UploadFile extends File
*/ */
public function getUploadExtension() public function getUploadExtension()
{ {
return pathinfo($this->_uploadName, PATHINFO_EXTENSION); return \pathinfo($this->_uploadName, PATHINFO_EXTENSION);
} }
/** /**
......
<?php <?php
namespace Webman; namespace Webman;
class Install class Install
...@@ -10,8 +11,9 @@ class Install ...@@ -10,8 +11,9 @@ class Install
*/ */
protected static $pathRelation = [ protected static $pathRelation = [
'start.php' => 'start.php', 'start.php' => 'start.php',
'windows.php' => 'windows.php',
'support/bootstrap.php' => 'support/bootstrap.php', 'support/bootstrap.php' => 'support/bootstrap.php',
'support/Plugin.php' => 'support/Plugin.php', 'support/helpers.php' => 'support/helpers.php',
]; ];
/** /**
...@@ -40,15 +42,14 @@ class Install ...@@ -40,15 +42,14 @@ class Install
{ {
foreach (static::$pathRelation as $source => $dest) { foreach (static::$pathRelation as $source => $dest) {
if ($pos = strrpos($dest, '/')) { if ($pos = strrpos($dest, '/')) {
$parent_dir = base_path().'/'.substr($dest, 0, $pos); $parent_dir = base_path() . '/' . substr($dest, 0, $pos);
if (!is_dir($parent_dir)) { if (!is_dir($parent_dir)) {
mkdir($parent_dir, 0777, true); mkdir($parent_dir, 0777, true);
} }
} }
copy_dir(__DIR__ . "/$source", base_path()."/$dest", true); copy_dir(__DIR__ . "/$source", base_path() . "/$dest", true);
echo "Create $dest echo "Create $dest\r\n";
";
} }
} }
} }
<?php <?php
namespace Webman;
use Psr\Container\ContainerInterface; namespace Webman;
use Webman\App;
/** /**
* This file is part of webman. * This file is part of webman.
...@@ -16,13 +14,8 @@ use Webman\App; ...@@ -16,13 +14,8 @@ use Webman\App;
* @link http://www.workerman.net/ * @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License * @license http://www.opensource.org/licenses/mit-license.php MIT License
*/ */
class Middleware class Middleware
{ {
/**
* @var ContainerInterface
*/
protected static $_container = null;
/** /**
* @var array * @var array
...@@ -30,17 +23,22 @@ class Middleware ...@@ -30,17 +23,22 @@ class Middleware
protected static $_instances = []; protected static $_instances = [];
/** /**
* @param $all_middlewares * @param array $all_middlewares
* @param string $plugin
* @return void
*/ */
public static function load($all_middlewares) public static function load($all_middlewares, string $plugin = '')
{ {
if (!\is_array($all_middlewares)) {
return;
}
foreach ($all_middlewares as $app_name => $middlewares) { foreach ($all_middlewares as $app_name => $middlewares) {
if (!\is_array($middlewares)) { if (!\is_array($middlewares)) {
throw new \RuntimeException('Bad middleware config'); throw new \RuntimeException('Bad middleware config');
} }
foreach ($middlewares as $class_name) { foreach ($middlewares as $class_name) {
if (\method_exists($class_name, 'process')) { if (\method_exists($class_name, 'process')) {
static::$_instances[$app_name][] = [static::container()->get($class_name), 'process']; static::$_instances[$plugin][$app_name][] = [$class_name, 'process'];
} else { } else {
// @todo Log // @todo Log
echo "middleware $class_name::process not exsits\n"; echo "middleware $class_name::process not exsits\n";
...@@ -50,42 +48,27 @@ class Middleware ...@@ -50,42 +48,27 @@ class Middleware
} }
/** /**
* @param $app_name * @param string $plugin
* @param string $app_name
* @param bool $with_global_middleware * @param bool $with_global_middleware
* @return array * @return array|mixed
*/ */
public static function getMiddleware($app_name, $with_global_middleware = true) public static function getMiddleware(string $plugin, string $app_name, bool $with_global_middleware = true)
{ {
$global_middleware = $with_global_middleware && isset(static::$_instances['']) ? static::$_instances[''] : []; $global_middleware = $with_global_middleware && isset(static::$_instances[$plugin]['']) ? static::$_instances[$plugin][''] : [];
if ($app_name === '') { if ($app_name === '') {
return \array_reverse($global_middleware); return \array_reverse($global_middleware);
} }
$app_middleware = static::$_instances[$app_name] ?? []; $app_middleware = static::$_instances[$plugin][$app_name] ?? [];
return \array_reverse(\array_merge($global_middleware, $app_middleware)); return \array_reverse(\array_merge($global_middleware, $app_middleware));
} }
/** /**
* @param $app_name * @deprecated
* @return bool * @return void
*/ */
public static function hasMiddleware($app_name) public static function container($_)
{ {
return isset(static::$_instances[$app_name]);
}
/**
* @param $container
* @return ContainerInterface
*/
public static function container($container = null)
{
if ($container) {
static::$_container = $container;
}
if (!static::$_container) {
static::$_container = App::container();
}
return static::$_container;
} }
} }
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
* @link http://www.workerman.net/ * @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License * @license http://www.opensource.org/licenses/mit-license.php MIT License
*/ */
namespace Webman; namespace Webman;
use Webman\Http\Request; use Webman\Http\Request;
......
...@@ -11,11 +11,11 @@ ...@@ -11,11 +11,11 @@
* @link http://www.workerman.net/ * @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License * @license http://www.opensource.org/licenses/mit-license.php MIT License
*/ */
namespace Webman; namespace Webman;
use FastRoute\Dispatcher\GroupCountBased; use FastRoute\Dispatcher\GroupCountBased;
use FastRoute\RouteCollector; use FastRoute\RouteCollector;
use Psr\Container\ContainerInterface;
use Webman\Route\Route as RouteObject; use Webman\Route\Route as RouteObject;
use function FastRoute\simpleDispatcher; use function FastRoute\simpleDispatcher;
...@@ -25,11 +25,6 @@ use function FastRoute\simpleDispatcher; ...@@ -25,11 +25,6 @@ use function FastRoute\simpleDispatcher;
*/ */
class Route class Route
{ {
/**
* @var ContainerInterface
*/
protected static $_container = null;
/** /**
* @var Route * @var Route
*/ */
...@@ -45,11 +40,6 @@ class Route ...@@ -45,11 +40,6 @@ class Route
*/ */
protected static $_collector = null; protected static $_collector = null;
/**
* @var bool
*/
protected static $_hasRoute = false;
/** /**
* @var null|callable * @var null|callable
*/ */
...@@ -68,7 +58,7 @@ class Route ...@@ -68,7 +58,7 @@ class Route
/** /**
* @var bool * @var bool
*/ */
protected static $_disableDefaultRoute = false; protected static $_disableDefaultRoute = [];
/** /**
* @var RouteObject[] * @var RouteObject[]
...@@ -81,103 +71,107 @@ class Route ...@@ -81,103 +71,107 @@ class Route
protected $_routes = []; protected $_routes = [];
/** /**
* @param $path * @param string $path
* @param $callback * @param callable $callback
* @return RouteObject * @return RouteObject
*/ */
public static function get($path, $callback) public static function get(string $path, $callback)
{ {
return static::addRoute('GET', $path, $callback); return static::addRoute('GET', $path, $callback);
} }
/** /**
* @param $path * @param string $path
* @param $callback * @param callable $callback
* @return RouteObject * @return RouteObject
*/ */
public static function post($path, $callback) public static function post(string $path, $callback)
{ {
return static::addRoute('POST', $path, $callback); return static::addRoute('POST', $path, $callback);
} }
/** /**
* @param $path * @param string $path
* @param $callback * @param callable $callback
* @return RouteObject * @return RouteObject
*/ */
public static function put($path, $callback) public static function put(string $path, $callback)
{ {
return static::addRoute('PUT', $path, $callback); return static::addRoute('PUT', $path, $callback);
} }
/** /**
* @param $path * @param string $path
* @param $callback * @param callable $callback
* @return RouteObject * @return RouteObject
*/ */
public static function patch($path, $callback) public static function patch(string $path, $callback)
{ {
return static::addRoute('PATCH', $path, $callback); return static::addRoute('PATCH', $path, $callback);
} }
/** /**
* @param $path * @param string $path
* @param $callback * @param callable $callback
* @return RouteObject * @return RouteObject
*/ */
public static function delete($path, $callback) public static function delete(string $path, $callback)
{ {
return static::addRoute('DELETE', $path, $callback); return static::addRoute('DELETE', $path, $callback);
} }
/** /**
* @param $path * @param string $path
* @param $callback * @param callable $callback
* @return RouteObject * @return RouteObject
*/ */
public static function head($path, $callback) public static function head(string $path, $callback)
{ {
return static::addRoute('HEAD', $path, $callback); return static::addRoute('HEAD', $path, $callback);
} }
/** /**
* @param $path * @param string $path
* @param $callback * @param callable $callback
* @return RouteObject * @return RouteObject
*/ */
public static function options($path, $callback) public static function options(string $path, $callback)
{ {
return static::addRoute('OPTIONS', $path, $callback); return static::addRoute('OPTIONS', $path, $callback);
} }
/** /**
* @param $path * @param string $path
* @param $callback * @param callable $callback
* @return RouteObject * @return RouteObject
*/ */
public static function any($path, $callback) public static function any(string $path, $callback)
{ {
return static::addRoute(['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'], $path, $callback); return static::addRoute(['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'], $path, $callback);
} }
/** /**
* @param $method * @param $method
* @param $path * @param string $path
* @param $callback * @param callable $callback
* @return RouteObject * @return RouteObject
*/ */
public static function add($method, $path, $callback) public static function add($method, string $path, $callback)
{ {
return static::addRoute($method, $path, $callback); return static::addRoute($method, $path, $callback);
} }
/** /**
* @param $path * @param string|callable $path
* @param $callback * @param callable|null $callback
* @return Route * @return static
*/ */
public static function group($path, $callback) public static function group($path, callable $callback = null)
{ {
if ($callback === null) {
$callback = $path;
$path = '';
}
$previous_group_prefix = static::$_groupPrefix; $previous_group_prefix = static::$_groupPrefix;
static::$_groupPrefix = $previous_group_prefix . $path; static::$_groupPrefix = $previous_group_prefix . $path;
$instance = static::$_instance = new static; $instance = static::$_instance = new static;
...@@ -196,37 +190,37 @@ class Route ...@@ -196,37 +190,37 @@ class Route
public static function resource(string $name, string $controller, array $options = []) public static function resource(string $name, string $controller, array $options = [])
{ {
$name = trim($name, '/'); $name = trim($name, '/');
if (is_array($options) && !empty($options)) { if (\is_array($options) && !empty($options)) {
$diff_options = array_diff($options, ['index', 'create', 'store', 'update', 'show', 'edit', 'destroy', 'recovery']); $diff_options = \array_diff($options, ['index', 'create', 'store', 'update', 'show', 'edit', 'destroy', 'recovery']);
if (!empty($diff_options)) { if (!empty($diff_options)) {
foreach ($diff_options as $action) { foreach ($diff_options as $action) {
static::any("/{$name}/{$action}[/{id}]", [$controller, $action])->name("{$name}.{$action}"); static::any("/{$name}/{$action}[/{id}]", [$controller, $action])->name("{$name}.{$action}");
} }
} }
// 注册路由 由于顺序不同会导致路由无效 因此不适用循环注册 // 注册路由 由于顺序不同会导致路由无效 因此不适用循环注册
if (in_array('index', $options)) static::get("/{$name}", [$controller, 'index'])->name("{$name}.index"); if (\in_array('index', $options)) static::get("/{$name}", [$controller, 'index'])->name("{$name}.index");
if (in_array('create', $options)) static::get("/{$name}/create", [$controller, 'create'])->name("{$name}.create"); if (\in_array('create', $options)) static::get("/{$name}/create", [$controller, 'create'])->name("{$name}.create");
if (in_array('store', $options)) static::post("/{$name}", [$controller, 'store'])->name("{$name}.store"); if (\in_array('store', $options)) static::post("/{$name}", [$controller, 'store'])->name("{$name}.store");
if (in_array('update', $options)) static::put("/{$name}/{id}", [$controller, 'update'])->name("{$name}.update"); if (\in_array('update', $options)) static::put("/{$name}/{id}", [$controller, 'update'])->name("{$name}.update");
if (in_array('show', $options)) static::get("/{$name}/{id}", [$controller, 'show'])->name("{$name}.show"); if (\in_array('show', $options)) static::get("/{$name}/{id}", [$controller, 'show'])->name("{$name}.show");
if (in_array('edit', $options)) static::get("/{$name}/{id}/edit", [$controller, 'edit'])->name("{$name}.edit"); if (\in_array('edit', $options)) static::get("/{$name}/{id}/edit", [$controller, 'edit'])->name("{$name}.edit");
if (in_array('destroy', $options)) static::delete("/{$name}/{id}", [$controller, 'destroy'])->name("{$name}.destroy"); if (\in_array('destroy', $options)) static::delete("/{$name}/{id}", [$controller, 'destroy'])->name("{$name}.destroy");
if (in_array('recovery', $options)) static::put("/{$name}/{id}/recovery", [$controller, 'recovery'])->name("{$name}.recovery"); if (\in_array('recovery', $options)) static::put("/{$name}/{id}/recovery", [$controller, 'recovery'])->name("{$name}.recovery");
} else { } else {
//为空时自动注册所有常用路由 //为空时自动注册所有常用路由
if (method_exists($controller, 'index')) static::get("/{$name}", [$controller, 'index'])->name("{$name}.index"); if (\method_exists($controller, 'index')) static::get("/{$name}", [$controller, 'index'])->name("{$name}.index");
if (method_exists($controller, 'create')) static::get("/{$name}/create", [$controller, 'create'])->name("{$name}.create"); if (\method_exists($controller, 'create')) static::get("/{$name}/create", [$controller, 'create'])->name("{$name}.create");
if (method_exists($controller, 'store')) static::post("/{$name}", [$controller, 'store'])->name("{$name}.store"); if (\method_exists($controller, 'store')) static::post("/{$name}", [$controller, 'store'])->name("{$name}.store");
if (method_exists($controller, 'update')) static::put("/{$name}/{id}", [$controller, 'update'])->name("{$name}.update"); if (\method_exists($controller, 'update')) static::put("/{$name}/{id}", [$controller, 'update'])->name("{$name}.update");
if (method_exists($controller, 'show')) static::get("/{$name}/{id}", [$controller, 'show'])->name("{$name}.show"); if (\method_exists($controller, 'show')) static::get("/{$name}/{id}", [$controller, 'show'])->name("{$name}.show");
if (method_exists($controller, 'edit')) static::get("/{$name}/{id}/edit", [$controller, 'edit'])->name("{$name}.edit"); if (\method_exists($controller, 'edit')) static::get("/{$name}/{id}/edit", [$controller, 'edit'])->name("{$name}.edit");
if (method_exists($controller, 'destroy')) static::delete("/{$name}/{id}", [$controller, 'destroy'])->name("{$name}.destroy"); if (\method_exists($controller, 'destroy')) static::delete("/{$name}/{id}", [$controller, 'destroy'])->name("{$name}.destroy");
if (method_exists($controller, 'recovery')) static::put("/{$name}/{id}/recovery", [$controller, 'recovery'])->name("{$name}.recovery"); if (\method_exists($controller, 'recovery')) static::put("/{$name}/{id}/recovery", [$controller, 'recovery'])->name("{$name}.recovery");
} }
} }
/** /**
* @return array * @return RouteObject[]
*/ */
public static function getRoutes() public static function getRoutes()
{ {
...@@ -235,18 +229,20 @@ class Route ...@@ -235,18 +229,20 @@ class Route
/** /**
* disableDefaultRoute. * disableDefaultRoute.
*
* @return void
*/ */
public static function disableDefaultRoute() public static function disableDefaultRoute($plugin = '')
{ {
static::$_disableDefaultRoute = true; static::$_disableDefaultRoute[$plugin] = true;
} }
/** /**
* @return bool * @return bool
*/ */
public static function hasDisableDefaultRoute() public static function hasDisableDefaultRoute($plugin = '')
{ {
return static::$_disableDefaultRoute === true; return static::$_disableDefaultRoute[$plugin] ?? false;
} }
/** /**
...@@ -272,7 +268,7 @@ class Route ...@@ -272,7 +268,7 @@ class Route
* @param $name * @param $name
* @param RouteObject $instance * @param RouteObject $instance
*/ */
public static function setByName($name, RouteObject $instance) public static function setByName(string $name, RouteObject $instance)
{ {
static::$_nameList[$name] = $instance; static::$_nameList[$name] = $instance;
} }
...@@ -281,57 +277,58 @@ class Route ...@@ -281,57 +277,58 @@ class Route
* @param $name * @param $name
* @return null|RouteObject * @return null|RouteObject
*/ */
public static function getByName($name) public static function getByName(string $name)
{ {
return static::$_nameList[$name] ?? null; return static::$_nameList[$name] ?? null;
} }
/** /**
* @param $method * @param string $method
* @param $path * @param string $path
* @return array * @return array
*/ */
public static function dispatch($method, $path) public static function dispatch($method, string $path)
{ {
return static::$_dispatcher->dispatch($method, $path); return static::$_dispatcher->dispatch($method, $path);
} }
/** /**
* @param $path * @param string $path
* @param $callback * @param callable $callback
* @return array|bool|callable * @return callable|false|string[]
*/ */
public static function convertToCallable($path, $callback) public static function convertToCallable(string $path, $callback)
{ {
if (\is_string($callback) && \strpos($callback, '@')) { if (\is_string($callback) && \strpos($callback, '@')) {
$callback = \explode('@', $callback, 2); $callback = \explode('@', $callback, 2);
} }
if (\is_array($callback)) { if (!\is_array($callback)) {
if (!\is_callable($callback)) {
$call_str = \is_scalar($callback) ? $callback : 'Closure';
echo "Route $path $call_str is not callable\n";
return false;
}
} else {
$callback = \array_values($callback); $callback = \array_values($callback);
if (isset($callback[1]) && \is_string($callback[0]) && \class_exists($callback[0])) { if (!isset($callback[1]) || !\class_exists($callback[0]) || !\method_exists($callback[0], $callback[1])) {
$callback = [static::container()->get($callback[0]), $callback[1]]; echo "Route $path " . \json_encode($callback) . " is not callable\n";
return false;
} }
} }
if (!\is_callable($callback)) {
echo "Route set to $path is not callable\n";
return false;
}
return $callback; return $callback;
} }
/** /**
* @param $methods * @param array $methods
* @param $path * @param string $path
* @param $callback * @param callable $callback
* @return RouteObject * @return RouteObject
*/ */
protected static function addRoute($methods, $path, $callback) protected static function addRoute($methods, string $path, $callback)
{ {
static::$_hasRoute = true;
$route = new RouteObject($methods, static::$_groupPrefix . $path, $callback); $route = new RouteObject($methods, static::$_groupPrefix . $path, $callback);
static::$_allRoutes[] = $route; static::$_allRoutes[] = $route;
...@@ -345,70 +342,77 @@ class Route ...@@ -345,70 +342,77 @@ class Route
} }
/** /**
* @return bool * @param array $paths
* @return void
*/ */
public static function load($config_path) public static function load($paths)
{ {
if (!is_dir($config_path)) { if (!\is_array($paths)) {
$config_path = pathinfo($config_path, PATHINFO_DIRNAME); return;
} }
static::$_dispatcher = simpleDispatcher(function (RouteCollector $route) use ($config_path) { static::$_dispatcher = simpleDispatcher(function (RouteCollector $route) use ($paths) {
Route::setCollector($route); Route::setCollector($route);
$route_config_file = $config_path . '/route.php'; foreach ($paths as $config_path) {
if (\is_file($route_config_file)) { $route_config_file = $config_path . '/route.php';
require_once $route_config_file; if (\is_file($route_config_file)) {
} require_once $route_config_file;
foreach (glob($config_path.'/plugin/*/*/route.php') as $file) { }
$app_config_file = pathinfo($file, PATHINFO_DIRNAME).'/app.php'; if (!is_dir($plugin_config_path = $config_path . '/plugin')) {
if (!is_file($app_config_file)) { return;
continue;
} }
$app_config = include $app_config_file; $dir_iterator = new \RecursiveDirectoryIterator($plugin_config_path, \FilesystemIterator::FOLLOW_SYMLINKS);
if (empty($app_config['enable'])) { $iterator = new \RecursiveIteratorIterator($dir_iterator);
continue; foreach ($iterator as $file) {
if ($file->getBaseName('.php') !== 'route') {
continue;
}
$app_config_file = pathinfo($file, PATHINFO_DIRNAME) . '/app.php';
if (!is_file($app_config_file)) {
continue;
}
$app_config = include $app_config_file;
if (empty($app_config['enable'])) {
continue;
}
require_once $file;
} }
require_once $file;
} }
}); });
return static::$_hasRoute;
} }
/** /**
* @param $route * @param RouteCollector $route
* @return void
*/ */
public static function setCollector($route) public static function setCollector(RouteCollector $route)
{ {
static::$_collector = $route; static::$_collector = $route;
} }
/** /**
* @param callable $callback * @param callable $callback
* @return void
*/ */
public static function fallback(callable $callback) { public static function fallback(callable $callback)
if (is_callable($callback)) { {
static::$_fallback = $callback; static::$_fallback = $callback;
}
} }
/** /**
* @return callable|null * @return callable|null
*/ */
public static function getFallback() { public static function getFallback()
return is_callable(static::$_fallback) ? static::$_fallback : null; {
return static::$_fallback;
} }
/** /**
* @param $container * @deprecated
* @return ContainerInterface * @return void
*/ */
public static function container($container = null) public static function container()
{ {
if ($container) {
static::$_container = $container;
}
if (!static::$_container) {
static::$_container = App::container();
}
return static::$_container;
} }
} }
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
* @link http://www.workerman.net/ * @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License * @license http://www.opensource.org/licenses/mit-license.php MIT License
*/ */
namespace Webman\Route; namespace Webman\Route;
use FastRoute\Dispatcher\GroupCountBased; use FastRoute\Dispatcher\GroupCountBased;
...@@ -48,14 +49,21 @@ class Route ...@@ -48,14 +49,21 @@ class Route
*/ */
protected $_middlewares = []; protected $_middlewares = [];
/**
* @var array
*/
protected $_params = [];
/** /**
* Route constructor. * Route constructor.
* @param $methods *
* @param $path * @param array $methods
* @param string $path
* @param callable $callback
*/ */
public function __construct($methods, $path, $callback) public function __construct($methods, string $path, $callback)
{ {
$this->_methods = (array) $methods; $this->_methods = (array)$methods;
$this->_path = $path; $this->_path = $path;
$this->_callback = $callback; $this->_callback = $callback;
} }
...@@ -69,10 +77,10 @@ class Route ...@@ -69,10 +77,10 @@ class Route
} }
/** /**
* @param $name * @param string $name
* @return $this * @return $this
*/ */
public function name($name) public function name(string $name)
{ {
$this->_name = $name; $this->_name = $name;
Router::setByName($name, $this); Router::setByName($name, $this);
...@@ -80,7 +88,7 @@ class Route ...@@ -80,7 +88,7 @@ class Route
} }
/** /**
* @param null $middleware * @param mixed $middleware
* @return $this|array * @return $this|array
*/ */
public function middleware($middleware = null) public function middleware($middleware = null)
...@@ -88,7 +96,7 @@ class Route ...@@ -88,7 +96,7 @@ class Route
if ($middleware === null) { if ($middleware === null) {
return $this->_middlewares; return $this->_middlewares;
} }
$this->_middlewares = array_merge($this->_middlewares, (array)$middleware); $this->_middlewares = \array_merge($this->_middlewares, (array)$middleware);
return $this; return $this;
} }
...@@ -124,6 +132,29 @@ class Route ...@@ -124,6 +132,29 @@ class Route
return $this->_middlewares; return $this->_middlewares;
} }
/**
* @param string|null $name
* @param $default
* @return array|mixed|null
*/
public function param(string $name = null, $default = null)
{
if ($name === null) {
return $this->_params;
}
return $this->_params[$name] ?? $default;
}
/**
* @param array $params
* @return $this
*/
public function setParams(array $params)
{
$this->_params = \array_merge($this->_params, $params);
return $this;
}
/** /**
* @param $parameters * @param $parameters
* @return string * @return string
...@@ -133,8 +164,8 @@ class Route ...@@ -133,8 +164,8 @@ class Route
if (empty($parameters)) { if (empty($parameters)) {
return $this->_path; return $this->_path;
} }
$path = str_replace(['[', ']'], '', $this->_path); $path = \str_replace(['[', ']'], '', $this->_path);
return preg_replace_callback('/\{(.*?)(?:\:[^\}]*?)*?\}/', function ($matches) use (&$parameters) { $path = \preg_replace_callback('/\{(.*?)(?:\:[^\}]*?)*?\}/', function ($matches) use (&$parameters) {
if (!$parameters) { if (!$parameters) {
return $matches[0]; return $matches[0];
} }
...@@ -151,6 +182,7 @@ class Route ...@@ -151,6 +182,7 @@ class Route
} }
return $matches[0]; return $matches[0];
}, $path); }, $path);
return \count($parameters) > 0 ? $path . '?' . http_build_query($parameters) : $path;
} }
} }
...@@ -11,17 +11,18 @@ ...@@ -11,17 +11,18 @@
* @link http://www.workerman.net/ * @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License * @license http://www.opensource.org/licenses/mit-license.php MIT License
*/ */
namespace Webman;
namespace Webman\Session;
use FastRoute\Dispatcher\GroupCountBased; use FastRoute\Dispatcher\GroupCountBased;
use FastRoute\RouteCollector; use FastRoute\RouteCollector;
use Workerman\Protocols\Http\Session\RedisSessionHandler as SessionHandler; use Workerman\Protocols\Http\Session\FileSessionHandler as FileHandler;
/** /**
* Class FileSessionHandler * Class FileSessionHandler
* @package Webman * @package Webman
*/ */
class RedisSessionHandler extends SessionHandler class FileSessionHandler extends FileHandler
{ {
} }
<?php
/**
* This file is part of webman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Webman\Session;
use Workerman\Protocols\Http\Session\RedisClusterSessionHandler as RedisClusterHandler;
class RedisClusterSessionHandler extends RedisClusterHandler
{
}
<?php
/**
* This file is part of webman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Webman\Session;
use FastRoute\Dispatcher\GroupCountBased;
use FastRoute\RouteCollector;
use Workerman\Protocols\Http\Session\RedisSessionHandler as RedisHandler;
/**
* Class FileSessionHandler
* @package Webman
*/
class RedisSessionHandler extends RedisHandler
{
}
<?php <?php
namespace Webman;
/** /**
* This file is part of webman. * This file is part of webman.
* *
...@@ -13,33 +12,27 @@ namespace Webman; ...@@ -13,33 +12,27 @@ namespace Webman;
* @license http://www.opensource.org/licenses/mit-license.php MIT License * @license http://www.opensource.org/licenses/mit-license.php MIT License
*/ */
namespace Webman;
class RedisClusterSessionHandler extends RedisSessionHandler /**
* Class Util
* @package Webman
*/
class Util
{ {
public function __construct($config)
{
$this->_maxLifeTime = (int)ini_get('session.gc_maxlifetime');
$timeout = $config['timeout'] ?? 2;
$read_timeout = $config['read_timeout'] ?? $timeout;
$persistent = $config['persistent'] ?? false;
$auth = $config['auth'] ?? '';
$args = [null, $config['host'], $timeout, $read_timeout, $persistent];
if ($auth) {
$args[] = $auth;
}
$this->_redis = new \RedisCluster(...$args);
if (empty($config['prefix'])) {
$config['prefix'] = 'redis_session_';
}
$this->_redis->setOption(\Redis::OPT_PREFIX, $config['prefix']);
}
/** /**
* {@inheritdoc} * @param string $path
* @return array
*/ */
public function read($session_id) public static function scanDir(string $base_path, $with_base_path = true): array
{ {
return $this->_redis->get($session_id); if (!is_dir($base_path)) {
return [];
}
$paths = \array_diff(\scandir($base_path), array('.', '..')) ?: [];
return $with_base_path ? \array_map(function($path) use ($base_path) {
return $base_path . DIRECTORY_SEPARATOR . $path;
}, $paths) : $paths;
} }
} }
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
* @link http://www.workerman.net/ * @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License * @license http://www.opensource.org/licenses/mit-license.php MIT License
*/ */
namespace Webman; namespace Webman;
interface View interface View
...@@ -21,5 +22,5 @@ interface View ...@@ -21,5 +22,5 @@ interface View
* @param null $app * @param null $app
* @return string * @return string
*/ */
static function render($template, $vars, $app = null); static function render(string $template, array $vars, string $app = null);
} }
#!/usr/bin/env php #!/usr/bin/env php
<?php <?php
require_once __DIR__ . '/vendor/autoload.php'; require_once __DIR__ . '/vendor/autoload.php';
Support\App::run();
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 (property_exists(Worker::class, 'stopTimeout')) {
Worker::$stopTimeout = $config['stop_timeout'] ?? 2;
}
if ($config['listen']) {
$worker = new Worker($config['listen'], $config['context']);
$property_map = [
'name',
'count',
'user',
'group',
'reusePort',
'transport',
'protocol'
];
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();
<?php
namespace support;
use Dotenv\Dotenv;
use Webman\Config;
use Webman\Util;
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http;
use Workerman\Worker;
class App
{
/**
* @return void
*/
public static function run()
{
ini_set('display_errors', 'on');
error_reporting(E_ALL);
if (class_exists(Dotenv::class) && file_exists(base_path() . '/.env')) {
if (method_exists(Dotenv::class, 'createUnsafeImmutable')) {
Dotenv::createUnsafeImmutable(base_path())->load();
} else {
Dotenv::createMutable(base_path())->load();
}
}
static::loadAllConfig(['route', 'container']);
$error_reporting = config('app.error_reporting');
if (isset($error_reporting)) {
error_reporting($error_reporting);
}
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 (property_exists(Worker::class, 'stopTimeout')) {
Worker::$stopTimeout = $config['stop_timeout'] ?? 2;
}
if ($config['listen']) {
$worker = new Worker($config['listen'], $config['context']);
$property_map = [
'name',
'count',
'user',
'group',
'reusePort',
'transport',
'protocol'
];
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 \Webman\App(config('app.request_class', Request::class), Log::channel('default'), app_path(), public_path());
$worker->onMessage = [$app, 'onMessage'];
[$app, 'onWorkerStart']($worker);
};
}
// 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) {
if (!is_array($project)) {
continue;
}
foreach ($project['process'] ?? [] as $process_name => $config) {
worker_start("plugin.$firm.$name.$process_name", $config);
}
}
foreach ($projects['process'] ?? [] as $process_name => $config) {
worker_start("plugin.$firm.$process_name", $config);
}
}
}
Worker::runAll();
}
/**
* @param array $excludes
* @return void
*/
public static function loadAllConfig(array $excludes = [])
{
Config::load(config_path(), $excludes);
$directory = base_path() . '/plugin';
foreach (Util::scanDir($directory, false) as $name) {
$dir = "$directory/$name/config";
if (\is_dir($dir)) {
Config::load($dir, $excludes, "plugin.$name");
}
}
}
}
...@@ -7,7 +7,7 @@ use Symfony\Component\Cache\Psr16Cache; ...@@ -7,7 +7,7 @@ use Symfony\Component\Cache\Psr16Cache;
/** /**
* Class Cache * Class Cache
* @package support\bootstrap * @package Support\Bootstrap
* *
* Strings methods * Strings methods
* @method static mixed get($key, $default = null) * @method static mixed get($key, $default = null)
......
...@@ -15,39 +15,33 @@ ...@@ -15,39 +15,33 @@
namespace support; namespace support;
use Psr\Container\ContainerInterface; use Psr\Container\ContainerInterface;
use Webman\Config;
/** /**
* Class Container * Class Container
* @package support * @package Support
* @method static mixed get($name) * @method static mixed get($name)
* @method static mixed make($name, array $parameters) * @method static mixed make($name, array $parameters)
* @method static bool has($name) * @method static bool has($name)
*/ */
class Container class Container
{ {
/**
* @var ContainerInterface
*/
protected static $_instance = null;
/** /**
* @return ContainerInterface * @return ContainerInterface
*/ */
public static function instance() public static function instance(string $plugin = '')
{ {
if (!static::$_instance) { return Config::get($plugin ? "plugin.$plugin.container" : 'container');
static::$_instance = include config_path() . '/container.php';
}
return static::$_instance;
} }
/** /**
* @param $name * @param string $name
* @param $arguments * @param array $arguments
* @return mixed * @return mixed
*/ */
public static function __callStatic($name, $arguments) public static function __callStatic(string $name, array $arguments)
{ {
return static::instance()->{$name}(... $arguments); $plugin = \Webman\App::getPluginByClass($name);
return static::instance($plugin)->{$name}(... $arguments);
} }
} }
\ No newline at end of file
...@@ -18,7 +18,7 @@ use Illuminate\Database\Capsule\Manager; ...@@ -18,7 +18,7 @@ use Illuminate\Database\Capsule\Manager;
/** /**
* Class Db * Class Db
* @package support * @package Support
* @method static array select(string $query, $bindings = [], $useReadPdo = true) * @method static array select(string $query, $bindings = [], $useReadPdo = true)
* @method static int insert(string $query, $bindings = []) * @method static int insert(string $query, $bindings = [])
* @method static int update(string $query, $bindings = []) * @method static int update(string $query, $bindings = [])
......
...@@ -21,7 +21,7 @@ use Monolog\Logger; ...@@ -21,7 +21,7 @@ use Monolog\Logger;
/** /**
* Class Log * Class Log
* @package support * @package Support
* *
* @method static void log($level, $message, array $context = []) * @method static void log($level, $message, array $context = [])
* @method static void debug($message, array $context = []) * @method static void debug($message, array $context = [])
...@@ -44,21 +44,22 @@ class Log ...@@ -44,21 +44,22 @@ class Log
* @param string $name * @param string $name
* @return Logger * @return Logger
*/ */
public static function channel($name = 'default') public static function channel(string $name = 'default')
{ {
if (!static::$_instance) { if (!isset(static::$_instance[$name])) {
$configs = config('log', []); $config = \config('log', [])[$name];
foreach ($configs as $channel => $config) { $handlers = self::handlers($config);
$handlers = self::handlers($config); $processors = self::processors($config);
$processors = self::processors($config); static::$_instance[$name] = new Logger($name, $handlers, $processors);
static::$_instance[$channel] = new Logger($channel,$handlers,$processors);
}
} }
return static::$_instance[$name]; return static::$_instance[$name];
} }
/**
protected static function handlers(array $config): array * @param array $config
* @return array
*/
protected static function handlers(array $config): array
{ {
$handlerConfigs = $config['handlers'] ?? [[]]; $handlerConfigs = $config['handlers'] ?? [[]];
$handlers = []; $handlers = [];
...@@ -74,7 +75,13 @@ class Log ...@@ -74,7 +75,13 @@ class Log
return $handlers; return $handlers;
} }
protected static function handler($class, $constructor, $formatterConfig): HandlerInterface /**
* @param string $class
* @param array $constructor
* @param array $formatterConfig
* @return HandlerInterface
*/
protected static function handler(string $class, array $constructor, array $formatterConfig): HandlerInterface
{ {
/** @var HandlerInterface $handler */ /** @var HandlerInterface $handler */
$handler = new $class(... \array_values($constructor)); $handler = new $class(... \array_values($constructor));
...@@ -92,29 +99,33 @@ class Log ...@@ -92,29 +99,33 @@ class Log
return $handler; return $handler;
} }
/**
* @param array $config
* @return array
*/
protected static function processors(array $config): array protected static function processors(array $config): array
{ {
$result = []; $result = [];
if (! isset($config['processors']) && isset($config['processor'])) { if (!isset($config['processors']) && isset($config['processor'])) {
$config['processors'] = [$config['processor']]; $config['processors'] = [$config['processor']];
} }
foreach ($config['processors'] ?? [] as $value) { foreach ($config['processors'] ?? [] as $value) {
if (is_array($value) && isset($value['class'])) { if (\is_array($value) && isset($value['class'])) {
$value = new $value['class'](... \array_values($value['constructor'] ?? []));; $value = new $value['class'](... \array_values($value['constructor'] ?? []));;
} }
$result[] = $value; $result[] = $value;
} }
return $result; return $result;
} }
/** /**
* @param $name * @param string $name
* @param $arguments * @param array $arguments
* @return mixed * @return mixed
*/ */
public static function __callStatic($name, $arguments) public static function __callStatic(string $name, array $arguments)
{ {
return static::channel('default')->{$name}(... $arguments); return static::channel('default')->{$name}(... $arguments);
} }
......
...@@ -16,6 +16,236 @@ namespace support; ...@@ -16,6 +16,236 @@ namespace support;
use Illuminate\Database\Eloquent\Model as BaseModel; use Illuminate\Database\Eloquent\Model as BaseModel;
/**
* @method static \Illuminate\Database\Eloquent\Model make($attributes = [])
* @method static \Illuminate\Database\Eloquent\Builder withGlobalScope($identifier, $scope)
* @method static \Illuminate\Database\Eloquent\Builder withoutGlobalScope($scope)
* @method static \Illuminate\Database\Eloquent\Builder withoutGlobalScopes($scopes = null)
* @method static array removedScopes()
* @method static \Illuminate\Database\Eloquent\Builder whereKey($id)
* @method static \Illuminate\Database\Eloquent\Builder whereKeyNot($id)
* @method static \Illuminate\Database\Eloquent\Builder where($column, $operator = null, $value = null, $boolean = 'and')
* @method static \Illuminate\Database\Eloquent\Model|null firstWhere($column, $operator = null, $value = null, $boolean = 'and')
* @method static \Illuminate\Database\Eloquent\Builder orWhere($column, $operator = null, $value = null)
* @method static \Illuminate\Database\Eloquent\Builder latest($column = null)
* @method static \Illuminate\Database\Eloquent\Builder oldest($column = null)
* @method static \Illuminate\Database\Eloquent\Collection hydrate($items)
* @method static \Illuminate\Database\Eloquent\Collection fromQuery($query, $bindings = [])
* @method static \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Collection[]|null find($id, $columns = [])
* @method static \Illuminate\Database\Eloquent\Collection findMany($ids, $columns = [])
* @method static \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Collection[] findOrFail($id, $columns = [])
* @method static \Illuminate\Database\Eloquent\Model findOrNew($id, $columns = [])
* @method static \Illuminate\Database\Eloquent\Model firstOrNew($attributes = [], $values = [])
* @method static \Illuminate\Database\Eloquent\Model firstOrCreate($attributes = [], $values = [])
* @method static \Illuminate\Database\Eloquent\Model updateOrCreate($attributes, $values = [])
* @method static \Illuminate\Database\Eloquent\Model firstOrFail($columns = [])
* @method static \Illuminate\Database\Eloquent\Model|mixed firstOr($columns = [], $callback = null)
* @method static \Illuminate\Database\Eloquent\Model sole($columns = [])
* @method static mixed value($column)
* @method static \Illuminate\Database\Eloquent\Collection[] get($columns = [])
* @method static \Illuminate\Database\Eloquent\Model[][] getModels($columns = [])
* @method static array eagerLoadRelations($models)
* @method static \Illuminate\Support\LazyCollection cursor()
* @method static \Illuminate\Support\Collection pluck($column, $key = null)
* @method static \Illuminate\Contracts\Pagination\LengthAwarePaginator paginate($perPage = null, $columns = [], $pageName = 'page', $page = null)
* @method static \Illuminate\Contracts\Pagination\Paginator simplePaginate($perPage = null, $columns = [], $pageName = 'page', $page = null)
* @method static \Illuminate\Contracts\Pagination\CursorPaginator cursorPaginate($perPage = null, $columns = [], $cursorName = 'cursor', $cursor = null)
* @method static \Illuminate\Database\Eloquent\Model|$this create($attributes = [])
* @method static \Illuminate\Database\Eloquent\Model|$this forceCreate($attributes)
* @method static int upsert($values, $uniqueBy, $update = null)
* @method static void onDelete($callback)
* @method static static|mixed scopes($scopes)
* @method static static applyScopes()
* @method static \Illuminate\Database\Eloquent\Builder without($relations)
* @method static \Illuminate\Database\Eloquent\Builder withOnly($relations)
* @method static \Illuminate\Database\Eloquent\Model newModelInstance($attributes = [])
* @method static \Illuminate\Database\Eloquent\Builder withCasts($casts)
* @method static \Illuminate\Database\Query\Builder getQuery()
* @method static \Illuminate\Database\Eloquent\Builder setQuery($query)
* @method static \Illuminate\Database\Query\Builder toBase()
* @method static array getEagerLoads()
* @method static \Illuminate\Database\Eloquent\Builder setEagerLoads($eagerLoad)
* @method static \Illuminate\Database\Eloquent\Model getModel()
* @method static \Illuminate\Database\Eloquent\Builder setModel($model)
* @method static \Closure getMacro($name)
* @method static bool hasMacro($name)
* @method static \Closure getGlobalMacro($name)
* @method static bool hasGlobalMacro($name)
* @method static static clone()
* @method static \Illuminate\Database\Eloquent\Builder has($relation, $operator = '>=', $count = 1, $boolean = 'and', $callback = null)
* @method static \Illuminate\Database\Eloquent\Builder orHas($relation, $operator = '>=', $count = 1)
* @method static \Illuminate\Database\Eloquent\Builder doesntHave($relation, $boolean = 'and', $callback = null)
* @method static \Illuminate\Database\Eloquent\Builder orDoesntHave($relation)
* @method static \Illuminate\Database\Eloquent\Builder whereHas($relation, $callback = null, $operator = '>=', $count = 1)
* @method static \Illuminate\Database\Eloquent\Builder orWhereHas($relation, $callback = null, $operator = '>=', $count = 1)
* @method static \Illuminate\Database\Eloquent\Builder whereDoesntHave($relation, $callback = null)
* @method static \Illuminate\Database\Eloquent\Builder orWhereDoesntHave($relation, $callback = null)
* @method static \Illuminate\Database\Eloquent\Builder hasMorph($relation, $types, $operator = '>=', $count = 1, $boolean = 'and', $callback = null)
* @method static \Illuminate\Database\Eloquent\Builder orHasMorph($relation, $types, $operator = '>=', $count = 1)
* @method static \Illuminate\Database\Eloquent\Builder doesntHaveMorph($relation, $types, $boolean = 'and', $callback = null)
* @method static \Illuminate\Database\Eloquent\Builder orDoesntHaveMorph($relation, $types)
* @method static \Illuminate\Database\Eloquent\Builder whereHasMorph($relation, $types, $callback = null, $operator = '>=', $count = 1)
* @method static \Illuminate\Database\Eloquent\Builder orWhereHasMorph($relation, $types, $callback = null, $operator = '>=', $count = 1)
* @method static \Illuminate\Database\Eloquent\Builder whereDoesntHaveMorph($relation, $types, $callback = null)
* @method static \Illuminate\Database\Eloquent\Builder orWhereDoesntHaveMorph($relation, $types, $callback = null)
* @method static \Illuminate\Database\Eloquent\Builder withAggregate($relations, $column, $function = null)
* @method static \Illuminate\Database\Eloquent\Builder withCount($relations)
* @method static \Illuminate\Database\Eloquent\Builder withMax($relation, $column)
* @method static \Illuminate\Database\Eloquent\Builder withMin($relation, $column)
* @method static \Illuminate\Database\Eloquent\Builder withSum($relation, $column)
* @method static \Illuminate\Database\Eloquent\Builder withAvg($relation, $column)
* @method static \Illuminate\Database\Eloquent\Builder withExists($relation)
* @method static \Illuminate\Database\Eloquent\Builder mergeConstraintsFrom($from)
* @method static \Illuminate\Support\Collection explain()
* @method static bool chunk($count, $callback)
* @method static \Illuminate\Support\Collection chunkMap($callback, $count = 1000)
* @method static bool each($callback, $count = 1000)
* @method static bool chunkById($count, $callback, $column = null, $alias = null)
* @method static bool eachById($callback, $count = 1000, $column = null, $alias = null)
* @method static \Illuminate\Support\LazyCollection lazy($chunkSize = 1000)
* @method static \Illuminate\Support\LazyCollection lazyById($chunkSize = 1000, $column = null, $alias = null)
* @method static \Illuminate\Database\Eloquent\Model|object|null first($columns = [])
* @method static \Illuminate\Database\Eloquent\Model|object|null baseSole($columns = [])
* @method static \Illuminate\Database\Eloquent\Builder tap($callback)
* @method static mixed when($value, $callback, $default = null)
* @method static mixed unless($value, $callback, $default = null)
* @method static \Illuminate\Database\Query\Builder select($columns = [])
* @method static \Illuminate\Database\Query\Builder selectSub($query, $as)
* @method static \Illuminate\Database\Query\Builder selectRaw($expression, $bindings = [])
* @method static \Illuminate\Database\Query\Builder fromSub($query, $as)
* @method static \Illuminate\Database\Query\Builder fromRaw($expression, $bindings = [])
* @method static \Illuminate\Database\Query\Builder addSelect($column)
* @method static \Illuminate\Database\Query\Builder distinct()
* @method static \Illuminate\Database\Query\Builder from($table, $as = null)
* @method static \Illuminate\Database\Query\Builder join($table, $first, $operator = null, $second = null, $type = 'inner', $where = false)
* @method static \Illuminate\Database\Query\Builder joinWhere($table, $first, $operator, $second, $type = 'inner')
* @method static \Illuminate\Database\Query\Builder joinSub($query, $as, $first, $operator = null, $second = null, $type = 'inner', $where = false)
* @method static \Illuminate\Database\Query\Builder leftJoin($table, $first, $operator = null, $second = null)
* @method static \Illuminate\Database\Query\Builder leftJoinWhere($table, $first, $operator, $second)
* @method static \Illuminate\Database\Query\Builder leftJoinSub($query, $as, $first, $operator = null, $second = null)
* @method static \Illuminate\Database\Query\Builder rightJoin($table, $first, $operator = null, $second = null)
* @method static \Illuminate\Database\Query\Builder rightJoinWhere($table, $first, $operator, $second)
* @method static \Illuminate\Database\Query\Builder rightJoinSub($query, $as, $first, $operator = null, $second = null)
* @method static \Illuminate\Database\Query\Builder crossJoin($table, $first = null, $operator = null, $second = null)
* @method static \Illuminate\Database\Query\Builder crossJoinSub($query, $as)
* @method static void mergeWheres($wheres, $bindings)
* @method static array prepareValueAndOperator($value, $operator, $useDefault = false)
* @method static \Illuminate\Database\Query\Builder whereColumn($first, $operator = null, $second = null, $boolean = 'and')
* @method static \Illuminate\Database\Query\Builder orWhereColumn($first, $operator = null, $second = null)
* @method static \Illuminate\Database\Query\Builder whereRaw($sql, $bindings = [], $boolean = 'and')
* @method static \Illuminate\Database\Query\Builder orWhereRaw($sql, $bindings = [])
* @method static \Illuminate\Database\Query\Builder whereIn($column, $values, $boolean = 'and', $not = false)
* @method static \Illuminate\Database\Query\Builder orWhereIn($column, $values)
* @method static \Illuminate\Database\Query\Builder whereNotIn($column, $values, $boolean = 'and')
* @method static \Illuminate\Database\Query\Builder orWhereNotIn($column, $values)
* @method static \Illuminate\Database\Query\Builder whereIntegerInRaw($column, $values, $boolean = 'and', $not = false)
* @method static \Illuminate\Database\Query\Builder orWhereIntegerInRaw($column, $values)
* @method static \Illuminate\Database\Query\Builder whereIntegerNotInRaw($column, $values, $boolean = 'and')
* @method static \Illuminate\Database\Query\Builder orWhereIntegerNotInRaw($column, $values)
* @method static \Illuminate\Database\Query\Builder whereNull($columns, $boolean = 'and', $not = false)
* @method static \Illuminate\Database\Query\Builder orWhereNull($column)
* @method static \Illuminate\Database\Query\Builder whereNotNull($columns, $boolean = 'and')
* @method static \Illuminate\Database\Query\Builder whereBetween($column, $values, $boolean = 'and', $not = false)
* @method static \Illuminate\Database\Query\Builder whereBetweenColumns($column, $values, $boolean = 'and', $not = false)
* @method static \Illuminate\Database\Query\Builder orWhereBetween($column, $values)
* @method static \Illuminate\Database\Query\Builder orWhereBetweenColumns($column, $values)
* @method static \Illuminate\Database\Query\Builder whereNotBetween($column, $values, $boolean = 'and')
* @method static \Illuminate\Database\Query\Builder whereNotBetweenColumns($column, $values, $boolean = 'and')
* @method static \Illuminate\Database\Query\Builder orWhereNotBetween($column, $values)
* @method static \Illuminate\Database\Query\Builder orWhereNotBetweenColumns($column, $values)
* @method static \Illuminate\Database\Query\Builder orWhereNotNull($column)
* @method static \Illuminate\Database\Query\Builder whereDate($column, $operator, $value = null, $boolean = 'and')
* @method static \Illuminate\Database\Query\Builder orWhereDate($column, $operator, $value = null)
* @method static \Illuminate\Database\Query\Builder whereTime($column, $operator, $value = null, $boolean = 'and')
* @method static \Illuminate\Database\Query\Builder orWhereTime($column, $operator, $value = null)
* @method static \Illuminate\Database\Query\Builder whereDay($column, $operator, $value = null, $boolean = 'and')
* @method static \Illuminate\Database\Query\Builder orWhereDay($column, $operator, $value = null)
* @method static \Illuminate\Database\Query\Builder whereMonth($column, $operator, $value = null, $boolean = 'and')
* @method static \Illuminate\Database\Query\Builder orWhereMonth($column, $operator, $value = null)
* @method static \Illuminate\Database\Query\Builder whereYear($column, $operator, $value = null, $boolean = 'and')
* @method static \Illuminate\Database\Query\Builder orWhereYear($column, $operator, $value = null)
* @method static \Illuminate\Database\Query\Builder whereNested($callback, $boolean = 'and')
* @method static \Illuminate\Database\Query\Builder forNestedWhere()
* @method static \Illuminate\Database\Query\Builder addNestedWhereQuery($query, $boolean = 'and')
* @method static \Illuminate\Database\Query\Builder whereExists($callback, $boolean = 'and', $not = false)
* @method static \Illuminate\Database\Query\Builder orWhereExists($callback, $not = false)
* @method static \Illuminate\Database\Query\Builder whereNotExists($callback, $boolean = 'and')
* @method static \Illuminate\Database\Query\Builder orWhereNotExists($callback)
* @method static \Illuminate\Database\Query\Builder addWhereExistsQuery($query, $boolean = 'and', $not = false)
* @method static \Illuminate\Database\Query\Builder whereRowValues($columns, $operator, $values, $boolean = 'and')
* @method static \Illuminate\Database\Query\Builder orWhereRowValues($columns, $operator, $values)
* @method static \Illuminate\Database\Query\Builder whereJsonContains($column, $value, $boolean = 'and', $not = false)
* @method static \Illuminate\Database\Query\Builder orWhereJsonContains($column, $value)
* @method static \Illuminate\Database\Query\Builder whereJsonDoesntContain($column, $value, $boolean = 'and')
* @method static \Illuminate\Database\Query\Builder orWhereJsonDoesntContain($column, $value)
* @method static \Illuminate\Database\Query\Builder whereJsonLength($column, $operator, $value = null, $boolean = 'and')
* @method static \Illuminate\Database\Query\Builder orWhereJsonLength($column, $operator, $value = null)
* @method static \Illuminate\Database\Query\Builder dynamicWhere($method, $parameters)
* @method static \Illuminate\Database\Query\Builder groupBy(...$groups)
* @method static \Illuminate\Database\Query\Builder groupByRaw($sql, $bindings = [])
* @method static \Illuminate\Database\Query\Builder having($column, $operator = null, $value = null, $boolean = 'and')
* @method static \Illuminate\Database\Query\Builder orHaving($column, $operator = null, $value = null)
* @method static \Illuminate\Database\Query\Builder havingBetween($column, $values, $boolean = 'and', $not = false)
* @method static \Illuminate\Database\Query\Builder havingRaw($sql, $bindings = [], $boolean = 'and')
* @method static \Illuminate\Database\Query\Builder orHavingRaw($sql, $bindings = [])
* @method static \Illuminate\Database\Query\Builder orderBy($column, $direction = 'asc')
* @method static \Illuminate\Database\Query\Builder orderByDesc($column)
* @method static \Illuminate\Database\Query\Builder inRandomOrder($seed = '')
* @method static \Illuminate\Database\Query\Builder orderByRaw($sql, $bindings = [])
* @method static \Illuminate\Database\Query\Builder skip($value)
* @method static \Illuminate\Database\Query\Builder offset($value)
* @method static \Illuminate\Database\Query\Builder take($value)
* @method static \Illuminate\Database\Query\Builder limit($value)
* @method static \Illuminate\Database\Query\Builder forPage($page, $perPage = 15)
* @method static \Illuminate\Database\Query\Builder forPageBeforeId($perPage = 15, $lastId = 0, $column = 'id')
* @method static \Illuminate\Database\Query\Builder forPageAfterId($perPage = 15, $lastId = 0, $column = 'id')
* @method static \Illuminate\Database\Query\Builder reorder($column = null, $direction = 'asc')
* @method static \Illuminate\Database\Query\Builder union($query, $all = false)
* @method static \Illuminate\Database\Query\Builder unionAll($query)
* @method static \Illuminate\Database\Query\Builder lock($value = true)
* @method static \Illuminate\Database\Query\Builder lockForUpdate()
* @method static \Illuminate\Database\Query\Builder sharedLock()
* @method static \Illuminate\Database\Query\Builder beforeQuery($callback)
* @method static void applyBeforeQueryCallbacks()
* @method static string toSql()
* @method static int getCountForPagination($columns = [])
* @method static string implode($column, $glue = '')
* @method static bool exists()
* @method static bool doesntExist()
* @method static mixed existsOr($callback)
* @method static mixed doesntExistOr($callback)
* @method static int count($columns = '*')
* @method static mixed min($column)
* @method static mixed max($column)
* @method static mixed sum($column)
* @method static mixed avg($column)
* @method static mixed average($column)
* @method static mixed aggregate($function, $columns = [])
* @method static float|int numericAggregate($function, $columns = [])
* @method static bool insert($values)
* @method static int insertOrIgnore($values)
* @method static int insertGetId($values, $sequence = null)
* @method static int insertUsing($columns, $query)
* @method static bool updateOrInsert($attributes, $values = [])
* @method static void truncate()
* @method static \Illuminate\Database\Query\Expression raw($value)
* @method static array getBindings()
* @method static array getRawBindings()
* @method static \Illuminate\Database\Query\Builder setBindings($bindings, $type = 'where')
* @method static \Illuminate\Database\Query\Builder addBinding($value, $type = 'where')
* @method static \Illuminate\Database\Query\Builder mergeBindings($query)
* @method static array cleanBindings($bindings)
* @method static \Illuminate\Database\Query\Processors\Processor getProcessor()
* @method static \Illuminate\Database\Query\Grammars\Grammar getGrammar()
* @method static \Illuminate\Database\Query\Builder useWritePdo()
* @method static static cloneWithout($properties)
* @method static static cloneWithoutBindings($except)
* @method static \Illuminate\Database\Query\Builder dump()
* @method static void dd()
* @method static void macro($name, $macro)
* @method static void mixin($mixin, $replace = true)
* @method static mixed macroCall($method, $parameters)
*/
class Model extends BaseModel class Model extends BaseModel
{ {
......
...@@ -4,27 +4,40 @@ namespace support; ...@@ -4,27 +4,40 @@ namespace support;
class Plugin class Plugin
{ {
/**
* @param $event
* @return void
*/
public static function install($event) public static function install($event)
{ {
static::findHepler(); static::findHepler();
$operation = $event->getOperation(); $operation = $event->getOperation();
$autoload = method_exists($operation, 'getPackage') ? $operation->getPackage()->getAutoload() : $operation->getTargetPackage()->getAutoload(); $autoload = \method_exists($operation, 'getPackage') ? $operation->getPackage()->getAutoload() : $operation->getTargetPackage()->getAutoload();
if (!isset($autoload['psr-4'])) { if (!isset($autoload['psr-4'])) {
return; return;
} }
$namespace = key($autoload['psr-4']); foreach ($autoload['psr-4'] as $namespace => $path) {
$install_function = "\\{$namespace}Install::install"; $install_function = "\\{$namespace}Install::install";
$plugin_const = "\\{$namespace}Install::WEBMAN_PLUGIN"; $plugin_const = "\\{$namespace}Install::WEBMAN_PLUGIN";
if (defined($plugin_const) && is_callable($install_function)) { if (\defined($plugin_const) && \is_callable($install_function)) {
$install_function(); $install_function();
}
} }
} }
/**
* @param $event
* @return void
*/
public static function update($event) public static function update($event)
{ {
static::install($event); static::install($event);
} }
/**
* @param $event
* @return void
*/
public static function uninstall($event) public static function uninstall($event)
{ {
static::findHepler(); static::findHepler();
...@@ -32,19 +45,23 @@ class Plugin ...@@ -32,19 +45,23 @@ class Plugin
if (!isset($autoload['psr-4'])) { if (!isset($autoload['psr-4'])) {
return; return;
} }
$namespace = key($autoload['psr-4']); foreach ($autoload['psr-4'] as $namespace => $path) {
$uninstall_function = "\\{$namespace}Install::uninstall"; $uninstall_function = "\\{$namespace}Install::uninstall";
$plugin_const = "\\{$namespace}Install::WEBMAN_PLUGIN"; $plugin_const = "\\{$namespace}Install::WEBMAN_PLUGIN";
if (defined($plugin_const) && is_callable($uninstall_function)) { if (defined($plugin_const) && is_callable($uninstall_function)) {
$uninstall_function(); $uninstall_function();
}
} }
} }
/**
* @return void
*/
protected static function findHepler() protected static function findHepler()
{ {
// Plugin.php in vendor // Plugin.php in vendor
$file = __DIR__ . '/../../../../../support/helpers.php'; $file = __DIR__ . '/../../../../../support/helpers.php';
if (is_file($file)) { if (\is_file($file)) {
require_once $file; require_once $file;
return; return;
} }
......
...@@ -14,13 +14,16 @@ ...@@ -14,13 +14,16 @@
namespace support; namespace support;
use Workerman\Timer; use Illuminate\Events\Dispatcher;
use Illuminate\Redis\Events\CommandExecuted;
use Illuminate\Redis\RedisManager; use Illuminate\Redis\RedisManager;
use Workerman\Timer;
use Workerman\Worker; use Workerman\Worker;
/** /**
* Class Redis * Class Redis
* @package support * @package Support
* *
* Strings methods * Strings methods
* @method static int append($key, $value) * @method static int append($key, $value)
...@@ -208,14 +211,39 @@ class Redis ...@@ -208,14 +211,39 @@ class Redis
*/ */
protected static $_instance = null; protected static $_instance = null;
/**
* need to install phpredis extension
*/
const PHPREDIS_CLIENT = 'phpredis';
/**
* need to install the 'predis/predis' packgage.
* cmd: composer install predis/predis
*/
const PREDIS_CLIENT = 'predis';
/**
* Support client collection
*/
static $_allowClient = [
self::PHPREDIS_CLIENT,
self::PREDIS_CLIENT
];
/** /**
* @return RedisManager * @return RedisManager
*/ */
public static function instance() public static function instance()
{ {
if (!static::$_instance) { if (!static::$_instance) {
$config = config('redis'); $config = \config('redis');
static::$_instance = new RedisManager('', 'phpredis', $config); $client = $config['client'] ?? self::PHPREDIS_CLIENT;
if (!\in_array($client, static::$_allowClient)) {
$client = self::PHPREDIS_CLIENT;
}
static::$_instance = new RedisManager('', $client, $config);
} }
return static::$_instance; return static::$_instance;
} }
...@@ -224,26 +252,27 @@ class Redis ...@@ -224,26 +252,27 @@ class Redis
* @param string $name * @param string $name
* @return \Illuminate\Redis\Connections\Connection * @return \Illuminate\Redis\Connections\Connection
*/ */
public static function connection($name = 'default') public static function connection(string $name = 'default')
{ {
static $timers = []; static $timers = [];
$connection = static::instance()->connection($name); $connection = static::instance()->connection($name);
if (!isset($timers[$name])) { if (!isset($timers[$name])) {
if (Worker::getAllWorkers()) { $timers[$name] = Worker::getAllWorkers() ? Timer::add(55, function () use ($connection) {
$timers[$name] = Timer::add(55, function () use ($connection) { $connection->get('ping');
$connection->get('ping'); }) : 1;
}); if (\class_exists(Dispatcher::class)) {
$connection->setEventDispatcher(new Dispatcher());
} }
} }
return $connection; return $connection;
} }
/** /**
* @param $name * @param string $name
* @param $arguments * @param array $arguments
* @return mixed * @return mixed
*/ */
public static function __callStatic($name, $arguments) public static function __callStatic(string $name, array $arguments)
{ {
return static::connection('default')->{$name}(... $arguments); return static::connection('default')->{$name}(... $arguments);
} }
......
...@@ -16,7 +16,7 @@ namespace support; ...@@ -16,7 +16,7 @@ namespace support;
/** /**
* Class Request * Class Request
* @package support * @package Support
*/ */
class Request extends \Webman\Http\Request class Request extends \Webman\Http\Request
{ {
......
...@@ -16,7 +16,7 @@ namespace support; ...@@ -16,7 +16,7 @@ namespace support;
/** /**
* Class Response * Class Response
* @package support * @package Support
*/ */
class Response extends \Webman\Http\Response class Response extends \Webman\Http\Response
{ {
......
...@@ -19,7 +19,7 @@ use Webman\Exception\NotFoundException; ...@@ -19,7 +19,7 @@ use Webman\Exception\NotFoundException;
/** /**
* Class Translation * Class Translation
* @package support * @package Support
* @method static string trans(?string $id, array $parameters = [], string $domain = null, string $locale = null) * @method static string trans(?string $id, array $parameters = [], string $domain = null, string $locale = null)
* @method static void setLocale(string $locale) * @method static void setLocale(string $locale)
* @method static string getLocale() * @method static string getLocale()
...@@ -28,24 +28,24 @@ class Translation ...@@ -28,24 +28,24 @@ class Translation
{ {
/** /**
* @var Translator * @var Translator[]
*/ */
protected static $_instance; protected static $_instance = [];
/** /**
* @return Translator * @return Translator
* @throws NotFoundException * @throws NotFoundException
*/ */
public static function instance() public static function instance(string $plugin = '')
{ {
if (!static::$_instance) { if (!isset(static::$_instance[$plugin])) {
$config = config('translation', []); $config = \config($plugin ? "plugin.$plugin.translation" : 'translation', []);
// Phar support. Compatible with the 'realpath' function in the phar file. // Phar support. Compatible with the 'realpath' function in the phar file.
if (!$translations_path = \get_realpath($config['path'])) { if (!$translations_path = \get_realpath($config['path'])) {
throw new NotFoundException("File {$config['path']} not found"); throw new NotFoundException("File {$config['path']} not found");
} }
static::$_instance = $translator = new Translator($config['locale']); static::$_instance[$plugin] = $translator = new Translator($config['locale']);
$translator->setFallbackLocales($config['fallback_locale']); $translator->setFallbackLocales($config['fallback_locale']);
$classes = [ $classes = [
...@@ -61,26 +61,29 @@ class Translation ...@@ -61,26 +61,29 @@ class Translation
foreach ($classes as $class => $opts) { foreach ($classes as $class => $opts) {
$translator->addLoader($opts['format'], new $class); $translator->addLoader($opts['format'], new $class);
foreach (glob($translations_path . DIRECTORY_SEPARATOR . '*' . DIRECTORY_SEPARATOR . '*' . $opts['extension']) as $file) { foreach (\glob($translations_path . DIRECTORY_SEPARATOR . '*' . DIRECTORY_SEPARATOR . '*' . $opts['extension']) as $file) {
$domain = basename($file, $opts['extension']); $domain = \basename($file, $opts['extension']);
$dir_name = pathinfo($file, PATHINFO_DIRNAME); $dir_name = \pathinfo($file, PATHINFO_DIRNAME);
$locale = substr(strrchr($dir_name, DIRECTORY_SEPARATOR), 1); $locale = \substr(strrchr($dir_name, DIRECTORY_SEPARATOR), 1);
if ($domain && $locale) { if ($domain && $locale) {
$translator->addResource($opts['format'], $file, $locale, $domain); $translator->addResource($opts['format'], $file, $locale, $domain);
} }
} }
} }
} }
return static::$_instance; return static::$_instance[$plugin];
} }
/** /**
* @param $name * @param string $name
* @param $arguments * @param array $arguments
* @return mixed * @return mixed
* @throws NotFoundException
*/ */
public static function __callStatic($name, $arguments) public static function __callStatic(string $name, array $arguments)
{ {
return static::instance()->{$name}(... $arguments); $request = \request();
$plugin = $request->plugin ?? '';
return static::instance($plugin)->{$name}(... $arguments);
} }
} }
...@@ -16,10 +16,16 @@ namespace support; ...@@ -16,10 +16,16 @@ namespace support;
class View class View
{ {
/**
* @param mixed $name
* @param mixed $value
* @return void
*/
public static function assign($name, $value = null) public static function assign($name, $value = null)
{ {
static $handler; $request = \request();
$handler = $handler ?: config('view.handler'); $plugin = $request->plugin ?? '';
$handler = \config($plugin ? "plugin.$plugin.view.handler" : 'view.handler');
$handler::assign($name, $value); $handler::assign($name, $value);
} }
} }
\ No newline at end of file
...@@ -13,10 +13,12 @@ ...@@ -13,10 +13,12 @@
*/ */
use Dotenv\Dotenv; use Dotenv\Dotenv;
use support\Container; use support\Log;
use Webman\Bootstrap;
use Webman\Config; use Webman\Config;
use Webman\Route; use Webman\Route;
use Webman\Middleware; use Webman\Middleware;
use Webman\Util;
$worker = $worker ?? null; $worker = $worker ?? null;
...@@ -24,7 +26,7 @@ if ($timezone = config('app.default_timezone')) { ...@@ -24,7 +26,7 @@ if ($timezone = config('app.default_timezone')) {
date_default_timezone_set($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) { if (error_reporting() & $level) {
throw new ErrorException($message, 0, $level, $file, $line); throw new ErrorException($message, 0, $level, $file, $line);
} }
...@@ -46,45 +48,85 @@ if (class_exists('Dotenv\Dotenv') && file_exists(base_path() . '/.env')) { ...@@ -46,45 +48,85 @@ if (class_exists('Dotenv\Dotenv') && file_exists(base_path() . '/.env')) {
} }
} }
Config::reload(config_path(), ['route', 'container']); Support\App::loadAllConfig(['route']);
foreach (config('autoload.files', []) as $file) {
include_once $file;
}
foreach (config('plugin', []) as $firm => $projects) { foreach (config('plugin', []) as $firm => $projects) {
foreach ($projects as $name => $project) { foreach ($projects as $name => $project) {
if (!is_array($project)) {
continue;
}
foreach ($project['autoload']['files'] ?? [] as $file) { foreach ($project['autoload']['files'] ?? [] as $file) {
include_once $file; include_once $file;
} }
} }
foreach ($projects['autoload']['files'] ?? [] as $file) {
include_once $file;
}
} }
foreach (config('autoload.files', []) as $file) { Middleware::load(config('middleware', []), '');
include_once $file;
}
$container = Container::instance();
Route::container($container);
Middleware::container($container);
Middleware::load(config('middleware', []));
foreach (config('plugin', []) as $firm => $projects) { foreach (config('plugin', []) as $firm => $projects) {
foreach ($projects as $name => $project) { 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) { 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); $class_name::start($worker);
} }
foreach (config('plugin', []) as $firm => $projects) { foreach (config('plugin', []) as $firm => $projects) {
foreach ($projects as $name => $project) { foreach ($projects as $name => $project) {
if (!is_array($project)) {
continue;
}
foreach ($project['bootstrap'] ?? [] as $class_name) { 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); $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);
...@@ -14,18 +14,21 @@ ...@@ -14,18 +14,21 @@
namespace support\bootstrap; namespace support\bootstrap;
use Webman\Bootstrap; use Illuminate\Container\Container;
use Illuminate\Database\Capsule\Manager as Capsule; use Illuminate\Database\Capsule\Manager as Capsule;
use Illuminate\Database\Connection;
use Illuminate\Events\Dispatcher; use Illuminate\Events\Dispatcher;
use Illuminate\Container\Container; use Illuminate\Pagination\Paginator;
use Jenssegers\Mongodb\Connection; use Jenssegers\Mongodb\Connection as MongodbConnection;
use Workerman\Worker;
use Workerman\Timer;
use support\Db; use support\Db;
use Throwable;
use Webman\Bootstrap;
use Workerman\Timer;
use Workerman\Worker;
/** /**
* Class Laravel * Class Laravel
* @package support\bootstrap * @package support\Bootstrap
*/ */
class LaravelDb implements Bootstrap class LaravelDb implements Bootstrap
{ {
...@@ -36,26 +39,26 @@ class LaravelDb implements Bootstrap ...@@ -36,26 +39,26 @@ class LaravelDb implements Bootstrap
*/ */
public static function start($worker) public static function start($worker)
{ {
if (!class_exists('\Illuminate\Database\Capsule\Manager')) { if (!class_exists(Capsule::class)) {
return; return;
} }
$connections = config('database.connections'); $config = \config('database', []);
$connections = $config['connections'] ?? [];
if (!$connections) { if (!$connections) {
return; return;
} }
$capsule = new Capsule; $capsule = new Capsule;
$configs = config('database');
$capsule->getDatabaseManager()->extend('mongodb', function ($config, $name) { $capsule->getDatabaseManager()->extend('mongodb', function ($config, $name) {
$config['name'] = $name; $config['name'] = $name;
return new MongodbConnection($config);
return new Connection($config);
}); });
if (isset($configs['default'])) { $default = $config['default'] ?? false;
$default_config = $connections[$configs['default']]; if ($default) {
$default_config = $connections[$config['default']];
$capsule->addConnection($default_config); $capsule->addConnection($default_config);
} }
...@@ -63,7 +66,7 @@ class LaravelDb implements Bootstrap ...@@ -63,7 +66,7 @@ class LaravelDb implements Bootstrap
$capsule->addConnection($config, $name); $capsule->addConnection($config, $name);
} }
if (class_exists('\Illuminate\Events\Dispatcher')) { if (\class_exists(Dispatcher::class)) {
$capsule->setEventDispatcher(new Dispatcher(new Container)); $capsule->setEventDispatcher(new Dispatcher(new Container));
} }
...@@ -73,13 +76,37 @@ class LaravelDb implements Bootstrap ...@@ -73,13 +76,37 @@ class LaravelDb implements Bootstrap
// Heartbeat // Heartbeat
if ($worker) { if ($worker) {
Timer::add(55, function () use ($connections) { Timer::add(55, function () use ($default, $connections) {
if (!class_exists(Connection::class, false)) {
return;
}
foreach ($connections as $key => $item) { foreach ($connections as $key => $item) {
if ($item['driver'] == 'mysql') { if ($item['driver'] == 'mysql') {
Db::connection($key)->select('select 1'); try {
if ($key == $default) {
Db::select('select 1');
} else {
Db::connection($key)->select('select 1');
}
} catch (Throwable $e) {
}
} }
} }
}); });
} }
// Paginator
if (class_exists(Paginator::class)) {
Paginator::queryStringResolver(function () {
return request()->queryString();
});
Paginator::currentPathResolver(function () {
return request()->path();
});
Paginator::currentPageResolver(function ($page_name = 'page') {
$page = (int)request()->input($page_name, 1);
return $page > 0 ? $page : 1;
});
}
} }
} }
...@@ -21,7 +21,7 @@ use Workerman\Worker; ...@@ -21,7 +21,7 @@ use Workerman\Worker;
/** /**
* Class Session * Class Session
* @package support * @package Support
*/ */
class Session implements Bootstrap class Session implements Bootstrap
{ {
...@@ -32,25 +32,28 @@ class Session implements Bootstrap ...@@ -32,25 +32,28 @@ class Session implements Bootstrap
*/ */
public static function start($worker) public static function start($worker)
{ {
$config = config('session'); $config = \config('session');
Http::sessionName($config['session_name']); if (\property_exists(SessionBase::class, 'name')) {
SessionBase::$name = $config['session_name'];
} else {
Http::sessionName($config['session_name']);
}
SessionBase::handlerClass($config['handler'], $config['config'][$config['type']]); SessionBase::handlerClass($config['handler'], $config['config'][$config['type']]);
if (property_exists(SessionBase::class, 'lifetime')) { $map = [
$map = [ 'auto_update_timestamp' => 'autoUpdateTimestamp',
'cookie_lifetime' => 'cookieLifetime', 'cookie_lifetime' => 'cookieLifetime',
'gc_probability' => 'gcProbability', 'gc_probability' => 'gcProbability',
'cookie_path' => 'cookiePath', 'cookie_path' => 'cookiePath',
'lifetime' => 'lifetime', 'http_only' => 'httpOnly',
'http_only' => 'httpOnly', 'same_site' => 'sameSite',
'domain' => 'domain', 'lifetime' => 'lifetime',
'secure' => 'secure', 'domain' => 'domain',
'same_site' => 'sameSite', 'secure' => 'secure',
]; ];
foreach ($map as $key => $name) { foreach ($map as $key => $name) {
if (isset($config[$key])) { if (isset($config[$key]) && \property_exists(SessionBase::class, $name)) {
SessionBase::${$name} = $config[$key]; SessionBase::${$name} = $config[$key];
}
} }
} }
} }
} }
\ No newline at end of file
...@@ -18,7 +18,7 @@ use Exception; ...@@ -18,7 +18,7 @@ use Exception;
/** /**
* Class BusinessException * Class BusinessException
* @package support\exception * @package Support\Exception
*/ */
class BusinessException extends Exception class BusinessException extends Exception
{ {
......
...@@ -14,14 +14,14 @@ ...@@ -14,14 +14,14 @@
namespace support\exception; namespace support\exception;
use Webman\Http\Request;
use Webman\Http\Response;
use Throwable; use Throwable;
use Webman\Exception\ExceptionHandler; use Webman\Exception\ExceptionHandler;
use Webman\Http\Request;
use Webman\Http\Response;
/** /**
* Class Handler * Class Handler
* @package support\exception * @package Support\Exception
*/ */
class Handler extends ExceptionHandler class Handler extends ExceptionHandler
{ {
......
...@@ -26,22 +26,22 @@ use Webman\Config; ...@@ -26,22 +26,22 @@ use Webman\Config;
use Webman\Route; use Webman\Route;
// Phar support. // Phar support.
if (is_phar()) { if (\is_phar()) {
define('BASE_PATH', dirname(__DIR__)); \define('BASE_PATH', dirname(__DIR__));
} else { } else {
define('BASE_PATH', realpath(__DIR__ . '/../')); \define('BASE_PATH', realpath(__DIR__ . '/../'));
} }
define('WEBMAN_VERSION', '1.3.0'); \define('WEBMAN_VERSION', '1.4');
/** /**
* @param $return_phar * @param $return_phar
* @return false|string * @return false|string
*/ */
function base_path($return_phar = true) function base_path(bool $return_phar = true)
{ {
static $real_path = ''; static $real_path = '';
if (!$real_path) { if (!$real_path) {
$real_path = is_phar() ? dirname(Phar::running(false)) : BASE_PATH; $real_path = \is_phar() ? \dirname(Phar::running(false)) : BASE_PATH;
} }
return $return_phar ? BASE_PATH : $real_path; return $return_phar ? BASE_PATH : $real_path;
} }
...@@ -61,7 +61,7 @@ function public_path() ...@@ -61,7 +61,7 @@ function public_path()
{ {
static $path = ''; static $path = '';
if (!$path) { if (!$path) {
$path = get_realpath(config('app.public_path', BASE_PATH . DIRECTORY_SEPARATOR . 'public')); $path = \config('app.public_path', BASE_PATH . DIRECTORY_SEPARATOR . 'public');
} }
return $path; return $path;
} }
...@@ -84,7 +84,7 @@ function runtime_path() ...@@ -84,7 +84,7 @@ function runtime_path()
{ {
static $path = ''; static $path = '';
if (!$path) { if (!$path) {
$path = get_realpath(config('app.runtime_path', BASE_PATH . DIRECTORY_SEPARATOR . 'runtime')); $path = \config('app.runtime_path', BASE_PATH . DIRECTORY_SEPARATOR . 'runtime');
} }
return $path; return $path;
} }
...@@ -95,7 +95,7 @@ function runtime_path() ...@@ -95,7 +95,7 @@ function runtime_path()
* @param string $body * @param string $body
* @return Response * @return Response
*/ */
function response($body = '', $status = 200, $headers = array()) function response($body = '', $status = 200, $headers = [])
{ {
return new Response($status, $headers, $body); return new Response($status, $headers, $body);
} }
...@@ -107,7 +107,7 @@ function response($body = '', $status = 200, $headers = array()) ...@@ -107,7 +107,7 @@ function response($body = '', $status = 200, $headers = array())
*/ */
function json($data, $options = JSON_UNESCAPED_UNICODE) function json($data, $options = JSON_UNESCAPED_UNICODE)
{ {
return new Response(200, ['Content-Type' => 'application/json'], json_encode($data, $options)); return new Response(200, ['Content-Type' => 'application/json'], \json_encode($data, $options));
} }
/** /**
...@@ -129,19 +129,19 @@ function xml($xml) ...@@ -129,19 +129,19 @@ function xml($xml)
*/ */
function jsonp($data, $callback_name = 'callback') function jsonp($data, $callback_name = 'callback')
{ {
if (!is_scalar($data) && null !== $data) { if (!\is_scalar($data) && null !== $data) {
$data = json_encode($data); $data = \json_encode($data);
} }
return new Response(200, [], "$callback_name($data)"); return new Response(200, [], "$callback_name($data)");
} }
/** /**
* @param $location * @param string $location
* @param int $status * @param int $status
* @param array $headers * @param array $headers
* @return Response * @return Response
*/ */
function redirect($location, $status = 302, $headers = []) function redirect(string $location, int $status = 302, array $headers = [])
{ {
$response = new Response($status, ['Location' => $location]); $response = new Response($status, ['Location' => $location]);
if (!empty($headers)) { if (!empty($headers)) {
...@@ -156,55 +156,55 @@ function redirect($location, $status = 302, $headers = []) ...@@ -156,55 +156,55 @@ function redirect($location, $status = 302, $headers = [])
* @param null $app * @param null $app
* @return Response * @return Response
*/ */
function view($template, $vars = [], $app = null) function view(string $template, array $vars = [], string $app = null)
{ {
static $handler; $request = \request();
if (null === $handler) { $plugin = $request->plugin ?? '';
$handler = config('view.handler'); $handler = \config($plugin ? "plugin.$plugin.view.handler" : 'view.handler');
}
return new Response(200, [], $handler::render($template, $vars, $app)); return new Response(200, [], $handler::render($template, $vars, $app));
} }
/** /**
* @param $template * @param string $template
* @param array $vars * @param array $vars
* @param null $app * @param string|null $app
* @return Response * @return Response
* @throws Throwable
*/ */
function raw_view($template, $vars = [], $app = null) function raw_view(string $template, array $vars = [], string $app = null)
{ {
return new Response(200, [], Raw::render($template, $vars, $app)); return new Response(200, [], Raw::render($template, $vars, $app));
} }
/** /**
* @param $template * @param string $template
* @param array $vars * @param array $vars
* @param null $app * @param string|null $app
* @return Response * @return Response
*/ */
function blade_view($template, $vars = [], $app = null) function blade_view(string $template, array $vars = [], string $app = null)
{ {
return new Response(200, [], Blade::render($template, $vars, $app)); return new Response(200, [], Blade::render($template, $vars, $app));
} }
/** /**
* @param $template * @param string $template
* @param array $vars * @param array $vars
* @param null $app * @param string|null $app
* @return Response * @return Response
*/ */
function think_view($template, $vars = [], $app = null) function think_view(string $template, array $vars = [], string $app = null)
{ {
return new Response(200, [], ThinkPHP::render($template, $vars, $app)); return new Response(200, [], ThinkPHP::render($template, $vars, $app));
} }
/** /**
* @param $template * @param string $template
* @param array $vars * @param array $vars
* @param null $app * @param string|null $app
* @return Response * @return Response
*/ */
function twig_view($template, $vars = [], $app = null) function twig_view(string $template, array $vars = [], string $app = null)
{ {
return new Response(200, [], Twig::render($template, $vars, $app)); return new Response(200, [], Twig::render($template, $vars, $app));
} }
...@@ -218,21 +218,21 @@ function request() ...@@ -218,21 +218,21 @@ function request()
} }
/** /**
* @param $key * @param string|null $key
* @param null $default * @param $default
* @return mixed * @return array|mixed|null
*/ */
function config($key = null, $default = null) function config(string $key = null, $default = null)
{ {
return Config::get($key, $default); return Config::get($key, $default);
} }
/** /**
* @param $name * @param string $name
* @param ...$parameters * @param ...$parameters
* @return string * @return string
*/ */
function route($name, ...$parameters) function route(string $name, ...$parameters)
{ {
$route = Route::getByName($name); $route = Route::getByName($name);
if (!$route) { if (!$route) {
...@@ -243,8 +243,8 @@ function route($name, ...$parameters) ...@@ -243,8 +243,8 @@ function route($name, ...$parameters)
return $route->url(); return $route->url();
} }
if (is_array(current($parameters))) { if (\is_array(\current($parameters))) {
$parameters = current($parameters); $parameters = \current($parameters);
} }
return $route->url($parameters); return $route->url($parameters);
...@@ -257,7 +257,7 @@ function route($name, ...$parameters) ...@@ -257,7 +257,7 @@ function route($name, ...$parameters)
*/ */
function session($key = null, $default = null) function session($key = null, $default = null)
{ {
$session = request()->session(); $session = \request()->session();
if (null === $key) { if (null === $key) {
return $session; return $session;
} }
...@@ -280,7 +280,7 @@ function session($key = null, $default = null) ...@@ -280,7 +280,7 @@ function session($key = null, $default = null)
} }
/** /**
* @param null|string $id * @param string $id
* @param array $parameters * @param array $parameters
* @param string|null $domain * @param string|null $domain
* @param string|null $locale * @param string|null $locale
...@@ -311,48 +311,50 @@ function locale(string $locale = null) ...@@ -311,48 +311,50 @@ function locale(string $locale = null)
*/ */
function not_found() function not_found()
{ {
return new Response(404, [], file_get_contents(public_path() . '/404.html')); return new Response(404, [], \file_get_contents(public_path() . '/404.html'));
} }
/** /**
* Copy dir. * Copy dir.
* @param $source *
* @param $dest * @param string $source
* @param string $dest
* @param bool $overwrite * @param bool $overwrite
* @return void * @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)) { if (!is_dir($dest)) {
mkdir($dest); \mkdir($dest);
} }
$files = scandir($source); $files = \scandir($source);
foreach ($files as $file) { foreach ($files as $file) {
if ($file !== "." && $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))) { } else if (\file_exists($source) && ($overwrite || !\file_exists($dest))) {
copy($source, $dest); \copy($source, $dest);
} }
} }
/** /**
* Remove dir. * Remove dir.
* @param $dir *
* @param string $dir
* @return bool * @return bool
*/ */
function remove_dir($dir) function remove_dir(string $dir)
{ {
if (is_link($dir) || is_file($dir)) { if (\is_link($dir) || \is_file($dir)) {
return unlink($dir); return \unlink($dir);
} }
$files = array_diff(scandir($dir), array('.', '..')); $files = \array_diff(\scandir($dir), array('.', '..'));
foreach ($files as $file) { 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);
} }
/** /**
...@@ -372,12 +374,12 @@ function worker_bind($worker, $class) ...@@ -372,12 +374,12 @@ function worker_bind($worker, $class)
'onWebSocketConnect' 'onWebSocketConnect'
]; ];
foreach ($callback_map as $name) { foreach ($callback_map as $name) {
if (method_exists($class, $name)) { if (\method_exists($class, $name)) {
$worker->$name = [$class, $name]; $worker->$name = [$class, $name];
} }
} }
if (method_exists($class, 'onWorkerStart')) { if (\method_exists($class, 'onWorkerStart')) {
call_user_func([$class, 'onWorkerStart'], $worker); [$class, 'onWorkerStart']($worker);
} }
} }
...@@ -406,10 +408,10 @@ function worker_start($process_name, $config) ...@@ -406,10 +408,10 @@ function worker_start($process_name, $config)
} }
$worker->onWorkerStart = function ($worker) use ($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) { 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"; echo "process error: class {$server['handler']} not exists\r\n";
continue; continue;
} }
...@@ -418,18 +420,18 @@ function worker_start($process_name, $config) ...@@ -418,18 +420,18 @@ function worker_start($process_name, $config)
echo "listen: {$server['listen']}\n"; echo "listen: {$server['listen']}\n";
} }
$instance = Container::make($server['handler'], $server['constructor'] ?? []); $instance = Container::make($server['handler'], $server['constructor'] ?? []);
worker_bind($listen, $instance); \worker_bind($listen, $instance);
$listen->listen(); $listen->listen();
} }
if (isset($config['handler'])) { if (isset($config['handler'])) {
if (!class_exists($config['handler'])) { if (!\class_exists($config['handler'])) {
echo "process error: class {$config['handler']} not exists\r\n"; echo "process error: class {$config['handler']} not exists\r\n";
return; return;
} }
$instance = Container::make($config['handler'], $config['constructor'] ?? []); $instance = Container::make($config['handler'], $config['constructor'] ?? []);
worker_bind($worker, $instance); \worker_bind($worker, $instance);
} }
}; };
...@@ -444,10 +446,10 @@ function worker_start($process_name, $config) ...@@ -444,10 +446,10 @@ function worker_start($process_name, $config)
*/ */
function get_realpath(string $file_path): string function get_realpath(string $file_path): string
{ {
if (strpos($file_path, 'phar://') === 0) { if (\strpos($file_path, 'phar://') === 0) {
return $file_path; return $file_path;
} else { } else {
return realpath($file_path); return \realpath($file_path);
} }
} }
...@@ -456,7 +458,7 @@ function get_realpath(string $file_path): string ...@@ -456,7 +458,7 @@ function get_realpath(string $file_path): string
*/ */
function is_phar() function is_phar()
{ {
return class_exists(\Phar::class, false) && Phar::running(); return \class_exists(\Phar::class, false) && Phar::running();
} }
/** /**
...@@ -469,11 +471,11 @@ function cpu_count() ...@@ -469,11 +471,11 @@ function cpu_count()
return 1; return 1;
} }
$count = 4; $count = 4;
if (is_callable('shell_exec')) { if (\is_callable('shell_exec')) {
if (strtolower(PHP_OS) === 'darwin') { if (\strtolower(PHP_OS) === 'darwin') {
$count = (int)shell_exec('sysctl -n machdep.cpu.core_count'); $count = (int)\shell_exec('sysctl -n machdep.cpu.core_count');
} else { } else {
$count = (int)shell_exec('nproc'); $count = (int)\shell_exec('nproc');
} }
} }
return $count > 0 ? $count : 4; return $count > 0 ? $count : 4;
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* @license http://www.opensource.org/licenses/mit-license.php MIT License * @license http://www.opensource.org/licenses/mit-license.php MIT License
*/ */
namespace support\view; namespace support\View;
use Jenssegers\Blade\Blade as BladeView; use Jenssegers\Blade\Blade as BladeView;
use Webman\View; use Webman\View;
...@@ -20,7 +20,7 @@ use Webman\View; ...@@ -20,7 +20,7 @@ use Webman\View;
/** /**
* Class Blade * Class Blade
* composer require jenssegers/blade * composer require jenssegers/blade
* @package support\view * @package Support\View
*/ */
class Blade implements View class Blade implements View
{ {
...@@ -30,8 +30,8 @@ class Blade implements View ...@@ -30,8 +30,8 @@ class Blade implements View
protected static $_vars = []; protected static $_vars = [];
/** /**
* @param $name * @param string|array $name
* @param null $value * @param mixed $value
*/ */
public static function assign($name, $value = null) public static function assign($name, $value = null)
{ {
...@@ -39,17 +39,20 @@ class Blade implements View ...@@ -39,17 +39,20 @@ class Blade implements View
} }
/** /**
* @param $template * @param string $template
* @param $vars * @param array $vars
* @param string $app * @param string|null $app
* @return mixed * @return string
*/ */
public static function render($template, $vars, $app = null) public static function render(string $template, array $vars, string $app = null)
{ {
static $views = []; static $views = [];
$app = $app === null ? \request()->app : $app; $request = \request();
$plugin = $request->plugin ?? '';
$app = $app === null ? $request->app : $app;
$base_view_path = $plugin ? \base_path() . "/plugin/$plugin/app" : \app_path();
if (!isset($views[$app])) { if (!isset($views[$app])) {
$view_path = $app === '' ? \app_path() . '/view' : \app_path() . "/$app/view"; $view_path = $app === '' ? "$base_view_path/view" : "$base_view_path/$app/view";
$views[$app] = new BladeView($view_path, \runtime_path() . '/views'); $views[$app] = new BladeView($view_path, \runtime_path() . '/views');
} }
$vars = \array_merge(static::$_vars, $vars); $vars = \array_merge(static::$_vars, $vars);
......
...@@ -12,13 +12,14 @@ ...@@ -12,13 +12,14 @@
* @license http://www.opensource.org/licenses/mit-license.php MIT License * @license http://www.opensource.org/licenses/mit-license.php MIT License
*/ */
namespace support\view; namespace support\View;
use Webman\View; use Webman\View;
use Throwable;
/** /**
* Class Raw * Class Raw
* @package support\view * @package Support\View
*/ */
class Raw implements View class Raw implements View
{ {
...@@ -28,8 +29,8 @@ class Raw implements View ...@@ -28,8 +29,8 @@ class Raw implements View
protected static $_vars = []; protected static $_vars = [];
/** /**
* @param $name * @param string|array $name
* @param null $value * @param mixed $value
*/ */
public static function assign($name, $value = null) public static function assign($name, $value = null)
{ {
...@@ -37,29 +38,31 @@ class Raw implements View ...@@ -37,29 +38,31 @@ class Raw implements View
} }
/** /**
* @param $template * @param string $template
* @param $vars * @param array $vars
* @param null $app * @param string|null $app
* @return string * @return false|string
*/ */
public static function render($template, $vars, $app = null) public static function render(string $template, array $vars, string $app = null)
{ {
static $view_suffix; $request = \request();
$view_suffix = $view_suffix ?: \config('view.view_suffix', 'html'); $plugin = $request->plugin ?? '';
$app = $app === null ? \request()->app : $app; $config_prefix = $plugin ? "plugin.$plugin." : '';
if ($app === '') { $view_suffix = \config("{$config_prefix}view.options.view_suffix", 'html');
$view_path = \app_path() . "/view/$template.$view_suffix"; $app = $app === null ? $request->app : $app;
} else { $base_view_path = $plugin ? \base_path() . "/plugin/$plugin/app" : \app_path();
$view_path = \app_path() . "/$app/view/$template.$view_suffix"; $view_path = $app === '' ? "$base_view_path/view/$template.$view_suffix" : "$base_view_path/$app/view/$template.$view_suffix";
}
\extract(static::$_vars); \extract(static::$_vars, \EXTR_SKIP);
\extract($vars); \extract($vars, \EXTR_SKIP);
\ob_start(); \ob_start();
// Try to include php file. // Try to include php file.
try { try {
include $view_path; include $view_path;
} catch (\Throwable $e) { } catch (Throwable $e) {
echo $e; static::$_vars = [];
\ob_end_clean();
throw $e;
} }
static::$_vars = []; static::$_vars = [];
return \ob_get_clean(); return \ob_get_clean();
......
...@@ -12,14 +12,14 @@ ...@@ -12,14 +12,14 @@
* @license http://www.opensource.org/licenses/mit-license.php MIT License * @license http://www.opensource.org/licenses/mit-license.php MIT License
*/ */
namespace support\view; namespace support\View;
use think\Template; use think\Template;
use Webman\View; use Webman\View;
/** /**
* Class Blade * Class Blade
* @package support\view * @package Support\View
*/ */
class ThinkPHP implements View class ThinkPHP implements View
{ {
...@@ -29,8 +29,8 @@ class ThinkPHP implements View ...@@ -29,8 +29,8 @@ class ThinkPHP implements View
protected static $_vars = []; protected static $_vars = [];
/** /**
* @param $name * @param string|array $name
* @param null $value * @param mixed $value
*/ */
public static function assign($name, $value = null) public static function assign($name, $value = null)
{ {
...@@ -38,21 +38,26 @@ class ThinkPHP implements View ...@@ -38,21 +38,26 @@ class ThinkPHP implements View
} }
/** /**
* @param $template * @param string $template
* @param $vars * @param array $vars
* @param string $app * @param string|null $app
* @return mixed * @return false|string
*/ */
public static function render($template, $vars, $app = null) public static function render(string $template, array $vars, string $app = null)
{ {
$app = $app === null ? \request()->app : $app; $request = \request();
$view_path = $app === '' ? \app_path() . '/view/' : \app_path() . "/$app/view/"; $plugin = $request->plugin ?? '';
$app = $app === null ? $request->app : $app;
$config_prefix = $plugin ? "plugin.$plugin." : '';
$view_suffix = \config("{$config_prefix}view.options.view_suffix", 'html');
$base_view_path = $plugin ? \base_path() . "/plugin/$plugin/app" : \app_path();
$view_path = $app === '' ? "$base_view_path/view/" : "$base_view_path/$app/view/";
$default_options = [ $default_options = [
'view_path' => $view_path, 'view_path' => $view_path,
'cache_path' => \runtime_path() . '/views/', 'cache_path' => \runtime_path() . '/views/',
'view_suffix' => config('view.view_suffix', 'html') 'view_suffix' => $view_suffix
]; ];
$options = $default_options + \config('view.options', []); $options = $default_options + \config("{$config_prefix}view.options", []);
$views = new Template($options); $views = new Template($options);
\ob_start(); \ob_start();
$vars = \array_merge(static::$_vars, $vars); $vars = \array_merge(static::$_vars, $vars);
......
...@@ -12,15 +12,15 @@ ...@@ -12,15 +12,15 @@
* @license http://www.opensource.org/licenses/mit-license.php MIT License * @license http://www.opensource.org/licenses/mit-license.php MIT License
*/ */
namespace support\view; namespace support\View;
use Twig\Loader\FilesystemLoader;
use Twig\Environment; use Twig\Environment;
use Twig\Loader\FilesystemLoader;
use Webman\View; use Webman\View;
/** /**
* Class Blade * Class Blade
* @package support\view * @package Support\View
*/ */
class Twig implements View class Twig implements View
{ {
...@@ -30,8 +30,8 @@ class Twig implements View ...@@ -30,8 +30,8 @@ class Twig implements View
protected static $_vars = []; protected static $_vars = [];
/** /**
* @param $name * @param string|array $name
* @param null $value * @param mixed $value
*/ */
public static function assign($name, $value = null) public static function assign($name, $value = null)
{ {
...@@ -39,22 +39,27 @@ class Twig implements View ...@@ -39,22 +39,27 @@ class Twig implements View
} }
/** /**
* @param $template * @param string $template
* @param $vars * @param array $vars
* @param string $app * @param string|null $app
* @return mixed * @return string
*/ */
public static function render($template, $vars, $app = null) public static function render(string $template, array $vars, string $app = null)
{ {
static $views = [], $view_suffix; static $views = [];
$view_suffix = $view_suffix ?: \config('view.view_suffix', 'html'); $request = \request();
$app = $app === null ? \request()->app : $app; $plugin = $request->plugin ?? '';
if (!isset($views[$app])) { $app = $app === null ? $request->app : $app;
$view_path = $app === '' ? \app_path() . '/view/' : \app_path() . "/$app/view/"; $config_prefix = $plugin ? "plugin.$plugin." : '';
$views[$app] = new Environment(new FilesystemLoader($view_path), \config('view.options', [])); $view_suffix = \config("{$config_prefix}view.options.view_suffix", 'html');
$key = "{$plugin}-{$request->app}";
if (!isset($views[$key])) {
$base_view_path = $plugin ? \base_path() . "/plugin/$plugin/app" : \app_path();
$view_path = $app === '' ? "$base_view_path/view/" : "$base_view_path/$app/view/";
$views[$key] = new Environment(new FilesystemLoader($view_path), \config("{$config_prefix}view.options", []));
} }
$vars = \array_merge(static::$_vars, $vars); $vars = \array_merge(static::$_vars, $vars);
$content = $views[$app]->render("$template.$view_suffix", $vars); $content = $views[$key]->render("$template.$view_suffix", $vars);
static::$_vars = []; static::$_vars = [];
return $content; return $content;
} }
......
<?php
/**
* Start file for windows
*/
require_once __DIR__ . '/vendor/autoload.php';
use process\Monitor;
use support\App;
use Dotenv\Dotenv;
use Workerman\Worker;
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();
}
}
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)) {
mkdir($runtime_process_path);
}
$process_files = [
__DIR__ . DIRECTORY_SEPARATOR . 'start.php'
];
foreach (config('process', []) as $process_name => $config) {
$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) {
$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);
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::runAll();
EOF;
$process_file = $runtime_process_path . DIRECTORY_SEPARATOR . "start_$process_param.php";
file_put_contents($process_file, $file_content);
return $process_file;
}
if ($monitor_config = config('process.monitor.constructor')) {
$monitor = new Monitor(...array_values($monitor_config));
}
function popen_processes($process_files)
{
$cmd = "php " . implode(' ', $process_files);
$descriptorspec = [STDIN, STDOUT, STDOUT];
$resource = proc_open($cmd, $descriptorspec, $pipes);
if (!$resource) {
exit("Can not execute $cmd\r\n");
}
return $resource;
}
$resource = popen_processes($process_files);
echo "\r\n";
while (1) {
sleep(1);
if (!empty($monitor) && $monitor->checkAllFilesChange()) {
$status = proc_get_status($resource);
$pid = $status['pid'];
shell_exec("taskkill /F /T /PID $pid");
proc_close($resource);
$resource = popen_processes($process_files);
}
}
#!/usr/bin/env php
<?php
use Webman\Config;
use Webman\Console\Command;
use Webman\Console\Util;
require_once __DIR__ . '/vendor/autoload.php';
if (!in_array($argv[1] ?? '', ['start', 'restart', 'stop', 'status', 'reload', 'connections'])) {
require_once __DIR__ . '/support/bootstrap.php';
} else {
if (class_exists('Support\App')) {
Support\App::loadAllConfig(['route']);
} else {
Config::reload(config_path(), ['route', 'container']);
}
}
$cli = new Command();
$cli->setName('webman cli');
$cli->installInternalCommands();
if (is_dir($command_path = Util::guessPath(app_path(), '/command', true))) {
$cli->installCommands($command_path);
}
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 ($projects as $name => $project) {
if (!is_array($project)) {
continue;
}
foreach ($project['command'] ?? [] as $command) {
$cli->add(new $command);
}
}
}
$cli->run();
...@@ -5,13 +5,27 @@ ...@@ -5,13 +5,27 @@
require_once __DIR__ . '/vendor/autoload.php'; require_once __DIR__ . '/vendor/autoload.php';
use process\Monitor; use process\Monitor;
use support\App;
use Dotenv\Dotenv;
use Workerman\Worker; use Workerman\Worker;
use Webman\Config;
ini_set('display_errors', 'on'); ini_set('display_errors', 'on');
error_reporting(E_ALL); 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'; $runtime_process_path = runtime_path() . DIRECTORY_SEPARATOR . '/windows';
if (!is_dir($runtime_process_path)) { if (!is_dir($runtime_process_path)) {
...@@ -21,41 +35,34 @@ $process_files = [ ...@@ -21,41 +35,34 @@ $process_files = [
__DIR__ . DIRECTORY_SEPARATOR . 'start.php' __DIR__ . DIRECTORY_SEPARATOR . 'start.php'
]; ];
foreach (config('process', []) as $process_name => $config) { foreach (config('process', []) as $process_name => $config) {
$file_content = <<<EOF $process_files[] = write_process_file($runtime_process_path, $process_name, '');
<?php
require_once __DIR__ . '/../../vendor/autoload.php';
use Workerman\Worker;
use Webman\Config;
ini_set('display_errors', 'on');
error_reporting(E_ALL);
if (is_callable('opcache_reset')) {
opcache_reset();
}
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);
} }
foreach (config('plugin', []) as $firm => $projects) { foreach (config('plugin', []) as $firm => $projects) {
foreach ($projects as $name => $project) { foreach ($projects as $name => $project) {
if (!is_array($project)) {
continue;
}
foreach ($project['process'] ?? [] as $process_name => $config) { 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 <?php
require_once __DIR__ . '/../../vendor/autoload.php'; require_once __DIR__ . '/../../vendor/autoload.php';
use Workerman\Worker; use Workerman\Worker;
use Webman\Config; use Webman\Config;
use support\App;
ini_set('display_errors', 'on'); ini_set('display_errors', 'on');
error_reporting(E_ALL); error_reporting(E_ALL);
...@@ -64,20 +71,25 @@ if (is_callable('opcache_reset')) { ...@@ -64,20 +71,25 @@ if (is_callable('opcache_reset')) {
opcache_reset(); opcache_reset();
} }
Config::load(config_path(), ['route', 'container']); 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(); Worker::runAll();
EOF; EOF;
$process_file = $runtime_process_path . DIRECTORY_SEPARATOR . "start_$process_name.php"; $process_file = $runtime_process_path . DIRECTORY_SEPARATOR . "start_$process_param.php";
$process_files[] = $process_file; file_put_contents($process_file, $file_content);
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) function popen_processes($process_files)
{ {
...@@ -94,7 +106,7 @@ $resource = popen_processes($process_files); ...@@ -94,7 +106,7 @@ $resource = popen_processes($process_files);
echo "\r\n"; echo "\r\n";
while (1) { while (1) {
sleep(1); sleep(1);
if ($monitor->checkAllFilesChange()) { if (!empty($monitor) && $monitor->checkAllFilesChange()) {
$status = proc_get_status($resource); $status = proc_get_status($resource);
$pid = $status['pid']; $pid = $status['pid'];
shell_exec("taskkill /F /T /PID $pid"); shell_exec("taskkill /F /T /PID $pid");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment