Compare commits

...

27 Commits

Author SHA1 Message Date
李东云
2e0e4feaa5 chore(release): 1.0.0-beta.9 2025-07-07 13:28:26 +08:00
李东云
c8b454540d build(deps): 更新依赖并添加 PHPSpec 支持
- 添加 Symfony polyfill-php84依赖
- 更新 rector/rector 至最新版本
- 添加 PHPSpec 相关配置和依赖
- 更新 composer.json 配置
- 调整项目结构,添加 spec 目录作为测试源

Signed-off-by: 李东云 <dongyu.li@luxcreo.ai>
2025-07-07 13:27:25 +08:00
李东云
bb11a1d8f4 chore(release): 1.0.0-beta.8 2025-03-04 02:34:32 +00:00
李东云
b4dcd01e8d build(composer): Update Dependencies 2025-03-04 02:33:58 +00:00
李东云
3b3502f763 feat(email): 添加邮件附件功能
- 在 EmailWillSent 事件中添加 attachmentPaths 和 attachments 属性
- 在 EmailService 中添加处理附件的逻辑
- 更新 EmailWillSentListener 以支持附件发送
2025-03-04 02:33:24 +00:00
李东云
768f2d79c0 chore(release): 1.0.0-beta.7 2025-03-03 09:59:24 +00:00
李东云
225bdedd23 feat(EmailService): 添加邮件附件功能并更新单元测试
- 在 EmailService 类的 sendHtml 方法中添加了附件处理逻辑
- 更新了 EmailServiceTest 单元测试,增加了附件发送的测试用例
- 优化了测试用例的结构,提高了可读性和可维护性
2025-03-03 09:57:04 +00:00
李东云
aaa4382ff2 build(devcontainer): 添加 Hyperf 开发套件核心配置文件
- 新增 devcontainer.json 配置文件,用于 Hyperf 框架的开发环境
- 配置了基础设置、挂载点、容器生命周期管理等
- 集成了多个 Visual Studio Code 扩展,提升开发效率
2025-03-03 09:32:35 +00:00
李东云
9a296c56e9 chore(release): 1.0.0-beta.6 2024-12-06 02:10:13 +00:00
李东云
2dace65933 fix(exceptions): 处理 HTTP 客户端和服务器异常
- 在 CommonHandler 中添加了对 GuzzleHttp 客户端和服务器异常的处理
- 解析异常响应内容,提取错误代码和消息
- 根据异常类型设置相应的状态码

Signed-off-by: 李东云 <dongyu.li@luxcreo.ai>
2024-12-06 10:07:42 +08:00
李东云
e8596c9d30 chore(release): 1.0.0-beta.5 2024-09-12 11:47:31 +00:00
李东云
b6dd7dd4ac feat(email): 对发送邮件增加密送,增加单独定制发件人的方法
Signed-off-by: 李东云 <dongyu.li@luxcreo.ai>
2024-09-12 19:47:14 +08:00
李东云
0283c7286a build(composer): 更新依赖
Signed-off-by: 李东云 <dongyu.li@luxcreo.ai>
2024-09-12 19:23:28 +08:00
李东云
e4105a285f chore(release): 1.0.0-beta.4 2024-06-23 12:55:58 +00:00
李东云
d20718db32 build(composer): 更新依赖
Signed-off-by: 李东云 <dongyu.li@luxcreo.ai>
2024-06-23 18:16:31 +08:00
李东云
d524fb4e89 fix(core-middleware): 修复 JsonResource 不走响应格式化的问题
Signed-off-by: 李东云 <dongyu.li@luxcreo.ai>
2024-06-23 18:13:41 +08:00
李东云
eeab8a258d chore(release): 1.0.0-beta.3 2024-05-17 06:05:09 +00:00
李东云
bac22a8ea6 build(composer): 更新依赖
Signed-off-by: 李东云 <dongyu.li@luxcreo.ai>
2024-05-17 14:04:48 +08:00
李东云
44c26b6491 fix(i18n): 在没有配置项目默认语言,且传入意料之外的语言时,默认为英文
Signed-off-by: 李东云 <dongyu.li@luxcreo.ai>
2024-05-17 14:04:09 +08:00
李东云
f422fb6b31 chore(release): 1.0.0-beta.2 2024-01-18 05:52:26 +00:00
李东云
762acbb368 fix(CoreMiddleware): 修复如果直接输出 ResponseInterface 实例会报错的问题
Signed-off-by: 李东云 <dongyu.li@luxcreo.ai>
2024-01-18 13:52:16 +08:00
李东云
2167fd209a perf(exception): 取消了必须是 apifox/postman 的设计
Signed-off-by: 李东云 <dongyu.li@luxcreo.ai>
2024-01-03 20:20:31 +08:00
李东云
fc9b41ef78 chore(release): 1.0.0-beta.1 2023-12-15 08:08:11 +00:00
李东云
da518799b3 fix(bin): 更新了迁移脚本的目录
Signed-off-by: 李东云 <dongyu.li@luxcreo.ai>
2023-12-15 16:08:00 +08:00
李东云
4d8a918898 chore(release): 1.0.0-beta.0 2023-12-15 08:00:49 +00:00
李东云
cfbb770559 build(release): 将版本号改为 beta
Signed-off-by: 李东云 <dongyu.li@luxcreo.ai>
2023-12-15 16:00:08 +08:00
李东云
01aa833537 fix(bin): 更新了迁移脚本的目录
Signed-off-by: 李东云 <dongyu.li@luxcreo.ai>
2023-12-15 15:58:23 +08:00
20 changed files with 3270 additions and 1678 deletions

View File

@@ -0,0 +1,49 @@
{
"name": "Hyperf Development Kit Core Dev Container",
"image": "harbor.luxcreo.cn/library/hyperf:8.1-swoole",
// 基础配置
"workspaceFolder": "/srv/www", // 对应 --workdir
"workspaceMount": "source=${localWorkspaceFolder},target=/srv/www,type=bind", // 主工作区挂载
// 附加挂载
"mounts": [
"source=${env:HOME}/.ssh,target=/root/.ssh,type=bind", // SSH 密钥挂载
"source=${env:HOME}/.gitconfig,target=/root/.gitconfig,type=bind" // SSH 密钥挂载
],
// 容器生命周期
"shutdownAction": "stopContainer", // 类似 --rm 的清理行为
"updateRemoteUserUID": true, // 确保用户 ID 同步
// 保留的必要 runArgs
"runArgs": [
"--pull=always", // 强制拉取最新镜像
"--name=hdk-core" // 容器命名(需保持唯一性)
],
// 初始化命令
"postCreateCommand": "echo 'Container initialized!'",
"customizations": {
"vscode": {
"extensions": [
"rid9.datetime",
"MS-CEINTL.vscode-language-pack-zh-hans",
"ms-azuretools.vscode-docker",
"janisdd.vscode-edit-csv",
"onecentlin.laravel-blade",
"DavidWang.ini-for-vscode",
"bmewburn.vscode-intelephense-client",
"mechatroner.rainbow-csv",
"Alibaba-Cloud.tongyi-lingma",
"atommaterial.a-file-icon-vscode",
"ParthR2031.colorful-comments",
"vincaslt.highlight-matching-tag",
"xabikos.JavaScriptSnippets",
"shufo.vscode-blade-formatter",
"dansysanalyst.pest-snippets",
"m1guelpf.better-pest",
"xoronic.pestfile",
"xdebug.php-debug",
"golang.go",
"cweijan.vscode-typora",
"ciceroisback.loam"
]
}
}
}

15
.idea/HDK-Core.iml generated
View File

@@ -4,6 +4,7 @@
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" packagePrefix="Singularity\HDK\Core\" />
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" packagePrefix="Singularity\HDK\Test\Core\" />
<sourceFolder url="file://$MODULE_DIR$/spec" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/runtime" />
<excludeFolder url="file://$MODULE_DIR$/vendor/adbario/php-dot-notation" />
<excludeFolder url="file://$MODULE_DIR$/vendor/alibabacloud/credentials" />
@@ -143,7 +144,6 @@
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-intl-idn" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-intl-normalizer" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-mbstring" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-php72" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-php73" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-php80" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-php81" />
@@ -177,6 +177,19 @@
<excludeFolder url="file://$MODULE_DIR$/vendor/webmozart/assert" />
<excludeFolder url="file://$MODULE_DIR$/vendor/carbonphp/carbon-doctrine-types" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-php82" />
<excludeFolder url="file://$MODULE_DIR$/vendor/clue/ndjson-react" />
<excludeFolder url="file://$MODULE_DIR$/vendor/evenement/evenement" />
<excludeFolder url="file://$MODULE_DIR$/vendor/react/cache" />
<excludeFolder url="file://$MODULE_DIR$/vendor/react/child-process" />
<excludeFolder url="file://$MODULE_DIR$/vendor/react/dns" />
<excludeFolder url="file://$MODULE_DIR$/vendor/react/event-loop" />
<excludeFolder url="file://$MODULE_DIR$/vendor/react/socket" />
<excludeFolder url="file://$MODULE_DIR$/vendor/react/stream" />
<excludeFolder url="file://$MODULE_DIR$/vendor/phpspec/php-diff" />
<excludeFolder url="file://$MODULE_DIR$/vendor/phpspec/phpspec" />
<excludeFolder url="file://$MODULE_DIR$/vendor/phpspec/prophecy" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-php84" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/yaml" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />

12
.idea/codeception.xml generated
View File

@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Codeception">
<option name="configurations">
<list>
<Configuration>
<option name="path" value="$PROJECT_DIR$/tests" />
</Configuration>
</list>
</option>
</component>
</project>

25
.idea/jsonSchemas.xml generated Normal file
View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JsonSchemaMappingsProjectConfiguration">
<state>
<map>
<entry key="composer.json">
<value>
<SchemaInfo>
<option name="name" value="composer.json" />
<option name="relativePathToSchema" value="https://getcomposer.org/schema.json" />
<option name="applicationDefined" value="true" />
<option name="patterns">
<list>
<Item>
<option name="path" value="composer.json" />
</Item>
</list>
</option>
</SchemaInfo>
</value>
</entry>
</map>
</state>
</component>
</project>

View File

@@ -2,6 +2,13 @@
<project version="4">
<component name="PhpTestFrameworkSettings">
<test_tools>
<tool tool_name="PHPSpec">
<settings>
<configurations>
<local_configuration executable_path="$PROJECT_DIR$/vendor/phpspec/phpspec/bin/phpspec" />
</configurations>
</settings>
</tool>
<tool tool_name="Pest">
<settings>
<configurations>

16
.idea/php.xml generated
View File

@@ -84,7 +84,6 @@
<path value="$PROJECT_DIR$/vendor/alibabacloud/tea-utils" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php81" />
<path value="$PROJECT_DIR$/vendor/alibabacloud/gateway-spi" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php72" />
<path value="$PROJECT_DIR$/vendor/alibabacloud/endpoint-util" />
<path value="$PROJECT_DIR$/vendor/symfony/translation" />
<path value="$PROJECT_DIR$/vendor/alibabacloud/dysmsapi-20170525" />
@@ -192,6 +191,21 @@
<path value="$PROJECT_DIR$/vendor/spatie/pest-plugin-test-time" />
<path value="$PROJECT_DIR$/vendor/carbonphp/carbon-doctrine-types" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php82" />
<path value="$PROJECT_DIR$/vendor/cooper/hyperf-pest" />
<path value="$PROJECT_DIR$/vendor/clue/ndjson-react" />
<path value="$PROJECT_DIR$/vendor/evenement/evenement" />
<path value="$PROJECT_DIR$/vendor/react/child-process" />
<path value="$PROJECT_DIR$/vendor/react/cache" />
<path value="$PROJECT_DIR$/vendor/react/dns" />
<path value="$PROJECT_DIR$/vendor/react/stream" />
<path value="$PROJECT_DIR$/vendor/react/event-loop" />
<path value="$PROJECT_DIR$/vendor/react/socket" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php72" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php84" />
<path value="$PROJECT_DIR$/vendor/symfony/yaml" />
<path value="$PROJECT_DIR$/vendor/phpspec/phpspec" />
<path value="$PROJECT_DIR$/vendor/phpspec/php-diff" />
<path value="$PROJECT_DIR$/vendor/phpspec/prophecy" />
</include_path>
</component>
<component name="PhpProjectSharedConfiguration" php_language_level="8.1" />

42
.idea/phpspec.xml generated
View File

@@ -5,48 +5,6 @@
<PhpSpecSuiteConfiguration>
<option name="myPath" value="$PROJECT_DIR$" />
</PhpSpecSuiteConfiguration>
<PhpSpecSuiteConfiguration>
<option name="myPath" value="$PROJECT_DIR$" />
</PhpSpecSuiteConfiguration>
<PhpSpecSuiteConfiguration>
<option name="myPath" value="$PROJECT_DIR$" />
</PhpSpecSuiteConfiguration>
<PhpSpecSuiteConfiguration>
<option name="myPath" value="$PROJECT_DIR$" />
</PhpSpecSuiteConfiguration>
<PhpSpecSuiteConfiguration>
<option name="myPath" value="$PROJECT_DIR$" />
</PhpSpecSuiteConfiguration>
<PhpSpecSuiteConfiguration>
<option name="myPath" value="$PROJECT_DIR$" />
</PhpSpecSuiteConfiguration>
<PhpSpecSuiteConfiguration>
<option name="myPath" value="$PROJECT_DIR$" />
</PhpSpecSuiteConfiguration>
<PhpSpecSuiteConfiguration>
<option name="myPath" value="$PROJECT_DIR$" />
</PhpSpecSuiteConfiguration>
<PhpSpecSuiteConfiguration>
<option name="myPath" value="$PROJECT_DIR$" />
</PhpSpecSuiteConfiguration>
<PhpSpecSuiteConfiguration>
<option name="myPath" value="$PROJECT_DIR$" />
</PhpSpecSuiteConfiguration>
<PhpSpecSuiteConfiguration>
<option name="myPath" value="$PROJECT_DIR$" />
</PhpSpecSuiteConfiguration>
<PhpSpecSuiteConfiguration>
<option name="myPath" value="$PROJECT_DIR$" />
</PhpSpecSuiteConfiguration>
<PhpSpecSuiteConfiguration>
<option name="myPath" value="$PROJECT_DIR$" />
</PhpSpecSuiteConfiguration>
<PhpSpecSuiteConfiguration>
<option name="myPath" value="$PROJECT_DIR$" />
</PhpSpecSuiteConfiguration>
<PhpSpecSuiteConfiguration>
<option name="myPath" value="$PROJECT_DIR$" />
</PhpSpecSuiteConfiguration>
</suites>
</component>
</project>

View File

@@ -1,4 +1,109 @@
# 版本更新日志
## [1.0.0-beta.9](http://124.126.16.154:8888/singularity/HyperfDevelopmentKitCore/compare/v1.0.0-beta.8...v1.0.0-beta.9) (2025-07-07)
### 📦‍ Build System | 打包构建
* **deps:** 更新依赖并添加 PHPSpec 支持 ([c8b4545](http://124.126.16.154:8888/singularity/HyperfDevelopmentKitCore/commit/c8b454540d2c4371c72f6cb79b5f65b97e7b92f2))
## [1.0.0-beta.8](http://124.126.16.154:8888/singularity/HyperfDevelopmentKitCore/compare/v1.0.0-beta.7...v1.0.0-beta.8) (2025-03-04)
### ✨ Features | 新功能
* **email:** 添加邮件附件功能 ([3b3502f](http://124.126.16.154:8888/singularity/HyperfDevelopmentKitCore/commit/3b3502f7634b48c31c3e7689cdcfe1f4b504b968))
### 📦‍ Build System | 打包构建
* **composer:** Update Dependencies ([b4dcd01](http://124.126.16.154:8888/singularity/HyperfDevelopmentKitCore/commit/b4dcd01e8d1fcd2c1fa211ef2a54512593500780))
## [1.0.0-beta.7](http://124.126.16.154:8888/singularity/HyperfDevelopmentKitCore/compare/v1.0.0-beta.6...v1.0.0-beta.7) (2025-03-03)
### 📦‍ Build System | 打包构建
* **devcontainer:** 添加 Hyperf 开发套件核心配置文件 ([aaa4382](http://124.126.16.154:8888/singularity/HyperfDevelopmentKitCore/commit/aaa4382ff2c5105bc362777f62156b8383b67ed8))
### ✨ Features | 新功能
* **EmailService:** 添加邮件附件功能并更新单元测试 ([225bded](http://124.126.16.154:8888/singularity/HyperfDevelopmentKitCore/commit/225bdedd23b1655d5fb7260838fc8c60db5d8f9f))
## [1.0.0-beta.6](http://124.126.16.154:8888/singularity/HyperfDevelopmentKitCore/compare/v1.0.0-beta.5...v1.0.0-beta.6) (2024-12-06)
### 🐛 Bug Fixes | Bug 修复
* **exceptions:** 处理 HTTP 客户端和服务器异常 ([2dace65](http://124.126.16.154:8888/singularity/HyperfDevelopmentKitCore/commit/2dace65933d7361c1124f8c5c125a507894584fb))
## [1.0.0-beta.5](http://124.126.16.154:8888/singularity/HyperfDevelopmentKitCore/compare/v1.0.0-beta.4...v1.0.0-beta.5) (2024-09-12)
### 📦‍ Build System | 打包构建
* **composer:** 更新依赖 ([0283c72](http://124.126.16.154:8888/singularity/HyperfDevelopmentKitCore/commit/0283c7286a58104c0ea649820fdab2dc781053c9))
### ✨ Features | 新功能
* **email:** 对发送邮件增加密送,增加单独定制发件人的方法 ([b6dd7dd](http://124.126.16.154:8888/singularity/HyperfDevelopmentKitCore/commit/b6dd7dd4ace2623a4631d22fc4e6394e9d2ddda7))
## [1.0.0-beta.4](http://124.126.16.154:8888/singularity/HyperfDevelopmentKitCore/compare/v1.0.0-beta.3...v1.0.0-beta.4) (2024-06-23)
### 🐛 Bug Fixes | Bug 修复
* **core-middleware:** 修复 JsonResource 不走响应格式化的问题 ([d524fb4](http://124.126.16.154:8888/singularity/HyperfDevelopmentKitCore/commit/d524fb4e890dd06da8c4fe2f0853e34944cd0e28))
### 📦‍ Build System | 打包构建
* **composer:** 更新依赖 ([d20718d](http://124.126.16.154:8888/singularity/HyperfDevelopmentKitCore/commit/d20718db32a9dc05535ff66598475186e8016167))
## [1.0.0-beta.3](http://124.126.16.154:8888/singularity/HyperfDevelopmentKitCore/compare/v1.0.0-beta.2...v1.0.0-beta.3) (2024-05-17)
### 🐛 Bug Fixes | Bug 修复
* **i18n:** 在没有配置项目默认语言,且传入意料之外的语言时,默认为英文 ([44c26b6](http://124.126.16.154:8888/singularity/HyperfDevelopmentKitCore/commit/44c26b64918702062f28499d566eaa54d8aff491))
### 📦‍ Build System | 打包构建
* **composer:** 更新依赖 ([bac22a8](http://124.126.16.154:8888/singularity/HyperfDevelopmentKitCore/commit/bac22a8ea683c42f597e070e1395881b46b2bd83))
## [1.0.0-beta.2](http://124.126.16.154:8888/singularity/HyperfDevelopmentKitCore/compare/v1.0.0-beta.1...v1.0.0-beta.2) (2024-01-18)
### ⚡ Performance Improvements | 性能优化
* **exception:** 取消了必须是 apifox/postman 的设计 ([2167fd2](http://124.126.16.154:8888/singularity/HyperfDevelopmentKitCore/commit/2167fd209a3cc46ea77fc64909ff8adf71ec6ef0))
### 🐛 Bug Fixes | Bug 修复
* **CoreMiddleware:** 修复如果直接输出 ResponseInterface 实例会报错的问题 ([762acbb](http://124.126.16.154:8888/singularity/HyperfDevelopmentKitCore/commit/762acbb368d6a901478fe3d6b2a3e30793f2c57c))
## [1.0.0-beta.1](http://124.126.16.154:8888/singularity/HyperfDevelopmentKitCore/compare/v1.0.0-beta.0...v1.0.0-beta.1) (2023-12-15)
### 🐛 Bug Fixes | Bug 修复
* **bin:** 更新了迁移脚本的目录 ([da51879](http://124.126.16.154:8888/singularity/HyperfDevelopmentKitCore/commit/da518799b3b4301302217af1faa452adbcacf02b))
## [1.0.0-beta.0](http://124.126.16.154:8888/singularity/HyperfDevelopmentKitCore/compare/v1.0.0-alpha.19...v1.0.0-beta.0) (2023-12-15)
### 🐛 Bug Fixes | Bug 修复
* **bin:** 更新了迁移脚本的目录 ([01aa833](http://124.126.16.154:8888/singularity/HyperfDevelopmentKitCore/commit/01aa8335371fce4f7663eb1c16e4ef7f108e2bc5))
### 📦‍ Build System | 打包构建
* **release:** 将版本号改为 beta ([cfbb770](http://124.126.16.154:8888/singularity/HyperfDevelopmentKitCore/commit/cfbb770559e748c77d52e7d913398b1d2a1d8edd))
## [1.0.0-alpha.19](http://124.126.16.154:8888/singularity/HyperfDevelopmentKitCore/compare/v1.0.0-alpha.18...v1.0.0-alpha.19) (2023-12-15)

View File

@@ -1 +1 @@
1.0.0-alpha.19
1.0.0-beta.9

View File

@@ -43,6 +43,7 @@
"symfony/polyfill-php81": "^1.28",
"symfony/polyfill-php82": "^1.28",
"symfony/polyfill-php83": "^1.28",
"symfony/polyfill-php84": "^1.28",
"teapot/status-code": "^1.1.2"
},
"require-dev": {
@@ -59,8 +60,9 @@
"hyperf/testing": "^3.1",
"hyperf/validation": "3.1.*",
"pestphp/pest": "^2.23",
"phpspec/phpspec": "^7.5",
"phpstan/phpstan": "^1.10.49",
"rector/rector": "^0.15.25",
"rector/rector": "*",
"roave/security-advisories": "dev-latest",
"spatie/pest-plugin-test-time": "^2.0",
"swoole/ide-helper": "*",
@@ -107,7 +109,7 @@
"phpunit.xml"
]
},
"minimum-stability": "dev",
"minimum-stability": "beta",
"prefer-stable": true,
"scripts": {
"post-root-package-install": [],
@@ -125,10 +127,14 @@
]
},
"repositories": {
"nest": {
"type": "composer",
"url": "https://nest.doylee.cn/api/packages/HDK/composer"
},
"packagist": {
"type": "composer",
"url": "https://mirrors.aliyun.com/composer/"
}
},
"version": "1.0.0-alpha.19"
"version": "1.0.0-beta.9"
}

4421
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -16,12 +16,13 @@ use Rector\Renaming\Rector\Name\RenameClassRector;
use Rector\Renaming\ValueObject\MethodCallRename;
return static function (RectorConfig $rectorConfig): void {
defined('BASE_PATH') || define('BASE_PATH', dirname(__DIR__, 3));
$rectorConfig->importNames(true, false);
$rectorConfig->paths([
__DIR__ . '/app',
__DIR__ . '/config',
__DIR__ . '/tests',
BASE_PATH . '/app',
BASE_PATH . '/config',
BASE_PATH . '/tests',
]);
$rectorConfig

View File

@@ -2,4 +2,4 @@
docker run --rm -it \
-v $(pwd):/app -e "GIT_AUTHOR_NAME=$(git config user.name)" -e "EMAIL=$(git config user.email)" \
detouched/standard-version:latest -p=alpha $1
detouched/standard-version:latest -p=beta $1

View File

@@ -1,4 +1,5 @@
<?php
/**
* EmailWillSent.php@HDK-Core
*
@@ -9,6 +10,8 @@
namespace Singularity\HDK\Core\Events;
use Singularity\HDK\Core\Service\EmailService;
use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\Email;
/**
@@ -24,9 +27,9 @@ class EmailWillSent
{
public function __construct(
/**
* @var string|string[] $target
* @var Address|string|string[]|Address[] $target
*/
public string|array $target,
public Address|string|array $target,
/**
* @var non-empty-string $subject
@@ -39,10 +42,19 @@ class EmailWillSent
public string $content,
/**
* 抄送
*
* @var string[] $cc
*/
public array $cc = [],
/**
* 密送
*
* @var string[] $bcc
*/
public array $bcc = [],
/**
* @var 'text'|'html' $type
*/
@@ -52,7 +64,23 @@ class EmailWillSent
* @var int
* @see Email::priority()
*/
public int $priority = Email::PRIORITY_NORMAL
) {
}
public int $priority = Email::PRIORITY_NORMAL,
/**
* @var EmailService|null
*/
public ?EmailService $sender = null,
/**
* 附件路径集合、含附件路径、文件名、文件类型的数组集合
* @var string[]|array{'path': string, 'name': string, 'mimeType': string}[] $attachmentPaths
*/
public array $attachmentPaths = [],
/**
* 附件内容集合、含附件内容、文件名、文件类型的数组集合
* @var string[]|array{'content': string, 'name': string, 'mimeType': string}[] $attachments
*/
public array $attachments = [],
) {}
}

View File

@@ -13,6 +13,8 @@ declare(strict_types=1);
namespace Singularity\HDK\Core\Exceptions\Handler;
use Carbon\Carbon;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Exception\ServerException;
use Hyperf\Codec\Json;
use Hyperf\Database\Exception\QueryException;
use Hyperf\Database\Model\ModelNotFoundException;
@@ -72,10 +74,8 @@ class CommonHandler extends ExceptionHandler
$message_name = config('common.response.message_name');
$is_testing = config('app_status') === true;
$this->request?->url();
$is_debug = $this->request?->hasHeader('Postman-Token') || str_starts_with(
$this->request?->header('User-Agent', ''),
'apifox'
);
$is_debug = $is_testing;
$error_type = $throwable::class;
$request_time = Carbon::now()->toDateTimeString();
$request_data = Json::encode($this->request?->getParsedBody());
@@ -95,6 +95,26 @@ class CommonHandler extends ExceptionHandler
$data['details'] = ['sql' => $throwable->getSql(), 'error' => $throwable->getMessage()];
}
}
if ($throwable instanceof ClientException) {
$content = $throwable->getResponse()->getBody()->getContents();
['errorCode' => $code, 'errorMsg' => $msg] = Json::decode($content);
$data = [
$code_name => $code,
$message_name => $msg,
];
$status_code = 400;
}
if ($throwable instanceof ServerException) {
$content = $throwable->getResponse()->getBody()->getContents();
['errorCode' => $code, 'errorMsg' => $msg] = Json::decode($content);
$data = [
$code_name => $code,
$message_name => $msg,
];
$status_code = 500;
}
// 101 请求方式错误
if ($throwable instanceof MethodNotAllowedHttpException) {
$message = explode(': ', $throwable->getMessage());

View File

@@ -22,7 +22,7 @@ enum Languages: string
return match (mb_strtolower($language)) {
'en', 'en_us', 'en-us', 'en-uk', 'en_uk' => self::EN,
'zh', 'zh_cn', 'zh-cn' => self::ZH_CN,
default => self::from(config('translation.locale')),
default => self::from(config('translation.locale') ?? 'en'),
};
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* EmailWillSentListener.php@HDK-Core
*
@@ -55,7 +56,8 @@ class EmailWillSentListener implements ListenerInterface
public function process(object $event): void
{
$stdoutLogger = $this->container->get(StdoutLoggerInterface::class);
$emailService = $this->container->get(EmailService::class);
// $emailService = $this->container->get(EmailService::class);
$emailService = $event->sender ?? EmailService::make();
try {
$event->type === 'html'
? $emailService->sendHtml(
@@ -63,6 +65,9 @@ class EmailWillSentListener implements ListenerInterface
subject: $event->subject,
html: $event->content,
cc: $event->cc,
bcc: $event->bcc,
attachmentPaths: $event->attachmentPaths,
attachments: $event->attachments,
priority: $event->priority
)
: $emailService->sendText(
@@ -70,6 +75,9 @@ class EmailWillSentListener implements ListenerInterface
subject: $event->subject,
text: $event->content,
cc: $event->cc,
bcc: $event->bcc,
attachmentPaths: $event->attachmentPaths,
attachments: $event->attachments,
priority: $event->priority
);

View File

@@ -18,6 +18,7 @@ use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpMessage\Server\ResponsePlusProxy;
use Hyperf\HttpMessage\Stream\SwooleStream;
use Hyperf\HttpServer\CoreMiddleware;
use Hyperf\Resource\Json\JsonResource;
use Lmc\HttpConstants\Header;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
@@ -47,14 +48,14 @@ class CommonCoreMiddleware extends CoreMiddleware
*/
protected function transferToResponse(
$response,
ServerRequestInterface $request
ServerRequestInterface $request,
): ResponsePlusInterface {
$style = $this->apiStyleService->get();
if ($style === ApiStyleService::RESTFUL) {
$response = $this->transferToRestfulResponse($response, $request);
} else {
$response = $this->transferToClassicResponse($response, $request);
if (!($response instanceof ResponseInterface) || $response instanceof JsonResource) {
$response = $style === ApiStyleService::RESTFUL
? $this->transferToRestfulResponse($response, $request)
: $this->transferToClassicResponse($response, $request);
}
return new ResponsePlusProxy($response);
@@ -68,7 +69,7 @@ class CommonCoreMiddleware extends CoreMiddleware
*/
protected function transferToRestfulResponse(
null|array|Arrayable|Jsonable|ResponseInterface|string $response,
ServerRequestInterface $request
ServerRequestInterface $request,
): ResponseInterface {
// 分页数据
if ($response instanceof LengthAwarePaginatorInterface) {
@@ -103,7 +104,7 @@ class CommonCoreMiddleware extends CoreMiddleware
*/
protected function transferToClassicResponse(
null|array|Arrayable|Jsonable|ResponseInterface|string $response,
ServerRequestInterface $request
ServerRequestInterface $request,
): ResponseInterface {
$code_name = config('common.response.code_name');
$message_name = config('common.response.message_name');
@@ -162,6 +163,9 @@ class CommonCoreMiddleware extends CoreMiddleware
new SwooleStream(Json::encode($response))
);
}
if ($response instanceof ResponseInterface) {
return $response;
}
// 其他默认按字符串处理
return $this->response()->withAddedHeader(Header::CONTENT_TYPE, 'text/plain')->withBody(
new SwooleStream((string)$response)

View File

@@ -45,6 +45,18 @@ class EmailService
);
}
public static function make(
?string $dsn = null,
?string $mailSenderName = null,
?string $mailSender = null,
): static {
return new static(
dsn: $dsn,
mailSenderName: $mailSenderName,
mailSender: $mailSender,
);
}
/**
* 发送邮件
*
@@ -67,29 +79,51 @@ class EmailService
}
/**
* @param string|array<string> $target
* @param string $subject
* @param string $text
* @param Address|string|array<string|Address> $target
* @param string $subject
* @param string $text
* @param array<string> $cc
* @param array $bcc
* @param int $priority
*
* @return bool
* @throws TransportExceptionInterface
*/
public function sendText(
string|array $target,
Address|string|array $target,
string $subject,
string $text,
array $cc = [],
array $bcc = [],
array $attachmentPaths = [],
array $attachments = [],
int $priority = Email::PRIORITY_NORMAL
): bool {
$email = (new Email())
->from(Address::create($this->from))
->to(...(is_array($target) ? $target : [$target]))
->cc(...$cc)
->bcc(...$bcc)
->priority($priority)
->subject($subject)
->text($text);
foreach ($attachmentPaths as $attachmentPath) {
if (is_string($attachmentPath)) {
$email = $email->attachFromPath($attachmentPath);
} else {
$email = $email->attachFromPath($attachmentPath['path'], $attachmentPath['name'] ?? null, $attachmentPath['mimeType'] ?? null);
}
}
foreach ($attachments as $attachment) {
if (is_string($attachment)) {
$email = $email->attach($attachment);
} else {
$email = $email->attach($attachment['content'], $attachment['name'] ?? null, $attachment['mimeType'] ?? null);
}
}
$this->mailer->send($email);
return true;
@@ -98,29 +132,51 @@ class EmailService
/**
* 以 HTML 格式发送邮件
*
* @param string|array<string> $target
* @param string $subject
* @param string $html
* @param Address|string|array<string|Address> $target
* @param string $subject
* @param string $html
* @param array<string> $cc
* @param int $priority
* @param array $bcc
* @param int $priority
*
* @return bool
* @throws TransportExceptionInterface
*/
public function sendHtml(
string|array $target,
Address|string|array $target,
string $subject,
string $html,
array $cc = [],
array $bcc = [],
array $attachmentPaths = [],
array $attachments = [],
int $priority = Email::PRIORITY_NORMAL
): bool {
$email = (new Email())
->from(Address::create($this->from))
->to(...(is_array($target) ? $target : [$target]))
->cc(...$cc)
->bcc(...$bcc)
->priority($priority)
->subject($subject)
->html($html);
foreach ($attachmentPaths as $attachmentPath) {
if (is_string($attachmentPath)) {
$email = $email->attachFromPath($attachmentPath);
} else {
$email = $email->attachFromPath($attachmentPath['path'], $attachmentPath['name'] ?? null, $attachmentPath['mimeType'] ?? null);
}
}
foreach ($attachments as $attachment) {
if (is_string($attachment)) {
$email = $email->attach($attachment);
} else {
$email = $email->attach($attachment['content'], $attachment['name'] ?? null, $attachment['mimeType'] ?? null);
}
}
$this->mailer->send($email);
return true;

View File

@@ -1,4 +1,5 @@
<?php
/**
* EmailServiceTest.php@HDK-Core
*
@@ -9,15 +10,19 @@
namespace Singularity\HDK\Test\Core\Service;
use PharIo\Manifest\Email;
use Singularity\HDK\Core\Service\EmailService;
use Symfony\Component\Mailer\Exception\TransportException;
$dsn = 'smtp://account@luxcreo.ai:Qfsd8866@smtp.qiye.aliyun.com:465';
$mail_sender_name = 'LuxCreo';
$mail_sender = 'account@luxcreo.ai';
$email = new EmailService($dsn, $mail_sender_name, $mail_sender);
use function Hyperf\Support\make;
it('assertions that send HTML is available', function () use ($email) {
it('assertions that send HTML is available', function () {
$dsn = 'smtp://account@luxcreo.ai:Qfsd8866@smtp.qiye.aliyun.com:465';
$mail_sender_name = 'LuxCreo';
$mail_sender = 'account@luxcreo.ai';
// $email = new EmailService($dsn, $mail_sender_name, $mail_sender);
$email = make(EmailService::class, ['dsn' => $dsn, 'mailSenderName' => $mail_sender_name, 'mailSender' => $mail_sender]);
$result = $email->sendHtml(
'dongyun.li@luxcreo.ai',
'HDK Unit Test HTML',
@@ -26,9 +31,15 @@ it('assertions that send HTML is available', function () use ($email) {
HTML
);
expect($result)->toBeTrue();
})->skip();
});
it('assertions that send Text is available', function () {
$dsn = 'smtp://account@luxcreo.ai:Qfsd8866@smtp.qiye.aliyun.com:465';
$mail_sender_name = 'LuxCreo';
$mail_sender = 'account@luxcreo.ai';
// $email = new EmailService($dsn, $mail_sender_name, $mail_sender);
$email = make(EmailService::class, ['dsn' => $dsn, 'mailSenderName' => $mail_sender_name, 'mailSender' => $mail_sender]);
it('assertions that send Text is available', function () use ($email) {
$result = $email->sendText(
'dongyun.li@luxcreo.ai',
'HDK Unit Test Text',
@@ -37,9 +48,15 @@ it('assertions that send Text is available', function () use ($email) {
Text
);
expect($result)->toBeTrue();
})->skip();
});
it('assertions Error Receiver can be catch', function () {
$dsn = 'smtp://account@luxcreo.ai:Qfsd8866@smtp.qiye.aliyun.com:465';
$mail_sender_name = 'LuxCreo';
$mail_sender = 'account@luxcreo.ai';
// $email = new EmailService($dsn, $mail_sender_name, $mail_sender);
$email = make(EmailService::class, ['dsn' => $dsn, 'mailSenderName' => $mail_sender_name, 'mailSender' => $mail_sender]);
it('assertions Error Receiver can be catch', function () use ($email) {
try {
$email->sendHtml(
'unknown@luxcreo.ai',
@@ -62,4 +79,30 @@ Text
} catch (TransportException $t) {
expect($t->getCode())->toBe(554);
}
})->skip('会报错必须运行在协程环境下');
});
it('should can contain attachment', function () {
$dsn = 'smtp://account@luxcreo.ai:Qfsd8866@smtp.qiye.aliyun.com:465';
$mail_sender_name = 'LuxCreo';
$mail_sender = 'account@luxcreo.ai';
// $email = new EmailService($dsn, $mail_sender_name, $mail_sender);
$email = make(EmailService::class, ['dsn' => $dsn, 'mailSenderName' => $mail_sender_name, 'mailSender' => $mail_sender]);
$email->sendHtml(
'dongyun.li@luxcreo.ai',
'HDK Unit Test HTML',
<<<HTML
<h1>Hello, World!</h1>
HTML,
[],
[],
[
[
'path' => __DIR__ . '/../../README.md',
'name' => 'README.md',
'mimeType' => 'text/markdown',
],
],
[]
);
})->only();