mirror of
https://gitee.com/hyperf/hyperf.git
synced 2024-11-29 18:27:44 +08:00
Merge branch 'master' into 2.1-merge
This commit is contained in:
commit
a8ea182146
@ -1,8 +1,47 @@
|
||||
# v2.0.22 - TBD
|
||||
# v2.0.24 - TBD
|
||||
|
||||
# v2.0.23 - 2020-12-14
|
||||
|
||||
## Added
|
||||
|
||||
- [#2872](https://github.com/hyperf/hyperf/pull/2872) Added `hyperf/phar` component.
|
||||
|
||||
## Fixed
|
||||
|
||||
- [#2952](https://github.com/hyperf/hyperf/pull/2952) Fixed bug that nacos config center does not works in coroutine server.
|
||||
|
||||
## Changed
|
||||
|
||||
- [#2934](https://github.com/hyperf/hyperf/pull/2934) Changed config file `scout.php` which search engine index is used as the model index name by default.
|
||||
- [#2958](https://github.com/hyperf/hyperf/pull/2958) Added NoneEngine as the default engine of view config.
|
||||
|
||||
## Optimized
|
||||
|
||||
- [#2951](https://github.com/hyperf/hyperf/pull/2951) Optimized code for model-cache, which will delete model cache only once, when using it in transaction.
|
||||
- [#2953](https://github.com/hyperf/hyperf/pull/2953) Hide `Swoole\ExitException` trace message in command.
|
||||
- [#2963](https://github.com/hyperf/hyperf/pull/2963) Removed `onStart` event from server default callbacks when the mode is `SWOOLE_BASE`.
|
||||
|
||||
# v2.0.22 - 2020-12-07
|
||||
|
||||
## Added
|
||||
|
||||
- [#2896](https://github.com/hyperf/hyperf/pull/2896) Support to define autoloaded view component classes and anonymous components.
|
||||
- [#2921](https://github.com/hyperf/hyperf/pull/2921) Added method `count()` for `Parallel`.
|
||||
|
||||
## Fixed
|
||||
|
||||
- [#2913](https://github.com/hyperf/hyperf/pull/2913) Fixed memory leak when using `with()` for ORM.
|
||||
- [#2915](https://github.com/hyperf/hyperf/pull/2915) Fixed bug that worker will be stoped when `onMessage` or `onClose` failed in websocket server.
|
||||
- [#2927](https://github.com/hyperf/hyperf/pull/2927) Fixed validation rule `alpha_dash` does not support `int`.
|
||||
|
||||
## Changed
|
||||
|
||||
- [#2918](https://github.com/hyperf/hyperf/pull/2918) Don't allow to open `server.settings.daemonize` configuration when using `hyperf/watcher`.
|
||||
- [#2930](https://github.com/hyperf/hyperf/pull/2930) Upgrade the minimum version of `php-amqplib` to `v2.9.2`.
|
||||
|
||||
## Optimized
|
||||
|
||||
- [#2931](https://github.com/hyperf/hyperf/pull/2931) Pass controller instance as first argument to method_exists function not the class namespace string.
|
||||
|
||||
# v2.0.21 - 2020-11-30
|
||||
|
||||
|
@ -63,7 +63,7 @@
|
||||
"nikic/php-parser": "^4.1",
|
||||
"overtrue/flysystem-cos": "^2.0|^3.0",
|
||||
"overtrue/flysystem-qiniu": "^1.0",
|
||||
"php-amqplib/php-amqplib": "^2.7",
|
||||
"php-amqplib/php-amqplib": "^2.9.2",
|
||||
"php-di/php-di": "^6.0",
|
||||
"phpspec/prophecy-phpunit": "^2.0",
|
||||
"phpstan/phpstan": "^0.12",
|
||||
@ -203,6 +203,7 @@
|
||||
"Hyperf\\Nats\\": "src/nats/src/",
|
||||
"Hyperf\\Nsq\\": "src/nsq/src/",
|
||||
"Hyperf\\Paginator\\": "src/paginator/src/",
|
||||
"Hyperf\\Phar\\": "src/phar/src/",
|
||||
"Hyperf\\Pool\\": "src/pool/src/",
|
||||
"Hyperf\\Process\\": "src/process/src/",
|
||||
"Hyperf\\Protocol\\": "src/protocol/src/",
|
||||
@ -281,6 +282,7 @@
|
||||
"HyperfTest\\Nats\\": "src/nats/tests/",
|
||||
"HyperfTest\\Nsq\\": "src/nsq/tests/",
|
||||
"HyperfTest\\Paginator\\": "src/paginator/tests/",
|
||||
"HyperfTest\\Phar\\": "src/phar/tests/",
|
||||
"HyperfTest\\Pool\\": "src/pool/tests/",
|
||||
"HyperfTest\\Process\\": "src/process/tests/",
|
||||
"HyperfTest\\Protocol\\": "src/protocol/tests/",
|
||||
@ -360,6 +362,7 @@
|
||||
"Hyperf\\Nats\\ConfigProvider",
|
||||
"Hyperf\\Nsq\\ConfigProvider",
|
||||
"Hyperf\\Paginator\\ConfigProvider",
|
||||
"Hyperf\\Phar\\ConfigProvider",
|
||||
"Hyperf\\Pool\\ConfigProvider",
|
||||
"Hyperf\\Process\\ConfigProvider",
|
||||
"Hyperf\\Protocol\\ConfigProvider",
|
||||
|
@ -255,7 +255,7 @@ use Hyperf\HttpServer\Annotation\AutoController;
|
||||
/**
|
||||
* @AutoController
|
||||
*/
|
||||
class QueueController extends Controller
|
||||
class QueueController extends AbstractController
|
||||
{
|
||||
/**
|
||||
* @Inject
|
||||
@ -327,7 +327,7 @@ use Hyperf\HttpServer\Annotation\AutoController;
|
||||
/**
|
||||
* @AutoController
|
||||
*/
|
||||
class QueueController extends Controller
|
||||
class QueueController extends AbstractController
|
||||
{
|
||||
/**
|
||||
* @Inject
|
||||
|
@ -1,5 +1,48 @@
|
||||
# 版本更新记录
|
||||
|
||||
# v2.0.23 - 2020-12-14
|
||||
|
||||
## 新增
|
||||
|
||||
- [#2872](https://github.com/hyperf/hyperf/pull/2872) 新增 `hyperf/phar` 组件,用于将 `Hyperf` 项目打包成 `phar`。
|
||||
|
||||
## 修复
|
||||
|
||||
- [#2952](https://github.com/hyperf/hyperf/pull/2952) 修复 `Nacos` 配置中心,在协程风格服务中无法正常使用的问题。
|
||||
|
||||
## 变更
|
||||
|
||||
- [#2934](https://github.com/hyperf/hyperf/pull/2934) 变更配置文件 `scout.php`,默认使用 `Elasticsearch` 索引作为模型索引。
|
||||
- [#2958](https://github.com/hyperf/hyperf/pull/2958) 变更 `view` 组件默认的渲染引擎为 `NoneEngine`。
|
||||
|
||||
## 优化
|
||||
|
||||
- [#2951](https://github.com/hyperf/hyperf/pull/2951) 优化 `model-cache` 组件,使其执行完多次事务后,只会删除一次缓存。
|
||||
- [#2953](https://github.com/hyperf/hyperf/pull/2953) 隐藏命令行因执行 `exit` 导致的异常 `Swoole\ExitException`。
|
||||
- [#2963](https://github.com/hyperf/hyperf/pull/2963) 当异步风格服务使用 `SWOOLE_BASE` 时,会从默认的事件回调中移除 `onStart` 事件。
|
||||
|
||||
# v2.0.22 - 2020-12-07
|
||||
|
||||
## 新增
|
||||
|
||||
- [#2896](https://github.com/hyperf/hyperf/pull/2896) 允许 `view-engine` 组件配置自定义加载类组件和匿名组件。
|
||||
- [#2921](https://github.com/hyperf/hyperf/pull/2921) 为 `Parallel` 增加 `count()` 方法,返回同时执行的个数。
|
||||
|
||||
## 修复
|
||||
|
||||
- [#2913](https://github.com/hyperf/hyperf/pull/2913) 修复使用 `ORM` 中的 `with` 预加载逻辑时,会因循环依赖导致内存泄露的问题。
|
||||
- [#2915](https://github.com/hyperf/hyperf/pull/2915) 修复 `WebSocket` 工作进程会因 `onMessage` or `onClose` 回调失败,导致进程退出的问题。
|
||||
- [#2927](https://github.com/hyperf/hyperf/pull/2927) 修复验证器规则 `alpha_dash` 不支持 `int` 的问题。
|
||||
|
||||
## 变更
|
||||
|
||||
- [#2918](https://github.com/hyperf/hyperf/pull/2918) 当使用 `watcher` 组件时,不可以开启 `daemonize`。
|
||||
- [#2930](https://github.com/hyperf/hyperf/pull/2930) 更新 `php-amqplib` 组件最低版本由 `v2.7` 到 `v2.9.2`。
|
||||
|
||||
## 优化
|
||||
|
||||
- [#2931](https://github.com/hyperf/hyperf/pull/2931) 判断控制器方法是否存在时,使用实际从容器中得到的对象,而非命名空间。
|
||||
|
||||
# v2.0.21 - 2020-11-30
|
||||
|
||||
## 新增
|
||||
|
@ -111,7 +111,7 @@ namespace App\Controller;
|
||||
use App\Constants\ErrorCode;
|
||||
use App\Exception\BusinessException;
|
||||
|
||||
class IndexController extends Controller
|
||||
class IndexController extends AbstractController
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
|
@ -183,7 +183,7 @@ class UserCollection extends ResourceCollection
|
||||
|
||||
```
|
||||
|
||||
你可以在者控制器中返回已定义的资源集合:
|
||||
你可以在控制器中返回已定义的资源集合:
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -891,7 +891,7 @@ class UserCollection extends ResourceCollection
|
||||
|
||||
#### 构造资源时添加元数据
|
||||
|
||||
你还可以在者控制器中构造资源实例时添加顶层数据。所有资源都可以使用 `additional` 方法来接受应该被添加到资源响应中的数据数组:
|
||||
你还可以在控制器中构造资源实例时添加顶层数据。所有资源都可以使用 `additional` 方法来接受应该被添加到资源响应中的数据数组:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
@ -95,7 +95,7 @@ namespace App\Controller;
|
||||
|
||||
use App\Exception\FooException;
|
||||
|
||||
class IndexController extends Controller
|
||||
class IndexController extends AbstractController
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
|
@ -55,7 +55,7 @@ class CalculatorService implements CalculatorServiceInterface
|
||||
|
||||
`@RpcService` 共有 `4` 个参数:
|
||||
`name` 属性为定义该服务的名称,这里定义一个全局唯一的名字即可,Hyperf 会根据该属性生成对应的 ID 注册到服务中心去;
|
||||
`protocol` 属性为定义该服务暴露的协议,目前仅支持 `jsonrpc` 和 `jsonrpc-http`,分别对应于 TCP 协议和 HTTP 协议下的两种协议,默认值为 `jsonrpc-http`,这里的值对应在 `Hyperf\Rpc\ProtocolManager` 里面注册的协议的 `key`,这两个本质上都是 JSON RPC 协议,区别在于数据格式化、数据打包、数据传输器等不同。
|
||||
`protocol` 属性为定义该服务暴露的协议,目前仅支持 `jsonrpc-http`, `jsonrpc`, `jsonrpc-tcp-length-check` ,分别对应于 HTTP 协议和 TCP 协议下的两种协议,默认值为 `jsonrpc-http`,这里的值对应在 `Hyperf\Rpc\ProtocolManager` 里面注册的协议的 `key`,它们本质上都是 JSON RPC 协议,区别在于数据格式化、数据打包、数据传输器等不同。
|
||||
`server` 属性为绑定该服务类发布所要承载的 `Server`,默认值为 `jsonrpc-http`,该属性对应 `config/autoload/server.php` 文件内 `servers` 下所对应的 `name`,这里也就意味着我们需要定义一个对应的 `Server`,我们下一章节具体阐述这里应该怎样去处理;
|
||||
`publishTo` 属性为定义该服务所要发布的服务中心,目前仅支持 `consul` 或为空,为空时代表不发布该服务到服务中心去,但也就意味着您需要手动处理服务发现的问题,当值为 `consul` 时需要对应配置好 [hyperf/consul](zh-cn/consul.md) 组件的相关配置,要使用此功能需安装 [hyperf/service-governance](https://github.com/hyperf/service-governance) 组件,具体可参考 [服务注册](zh-cn/service-register.md) 章节;
|
||||
|
||||
|
@ -59,7 +59,7 @@ use Hyperf\Nats\Driver\DriverInterface;
|
||||
/**
|
||||
* @AutoController(prefix="nats")
|
||||
*/
|
||||
class NatsController extends Controller
|
||||
class NatsController extends AbstractController
|
||||
{
|
||||
/**
|
||||
* @Inject
|
||||
@ -96,7 +96,7 @@ use Hyperf\Nats\Message;
|
||||
/**
|
||||
* @AutoController(prefix="nats")
|
||||
*/
|
||||
class NatsController extends Controller
|
||||
class NatsController extends AbstractController
|
||||
{
|
||||
/**
|
||||
* @Inject
|
||||
@ -135,7 +135,7 @@ use Hyperf\Nats\Message;
|
||||
/**
|
||||
* @AutoController(prefix="nats")
|
||||
*/
|
||||
class NatsController extends Controller
|
||||
class NatsController extends AbstractController
|
||||
{
|
||||
/**
|
||||
* @Inject
|
||||
|
@ -8,7 +8,9 @@ Hyperf 使用 [nikic/fast-route](https://github.com/nikic/FastRoute) 作为默
|
||||
不仅如此,框架还提供了极其强大和方便灵活的 `注解路由` 功能,关于路由的详情文档请查阅 [路由](zh-cn/router.md) 章节
|
||||
|
||||
### 通过配置文件定义路由
|
||||
|
||||
路由的文件位于 [hyperf-skeleton](https://github.com/hyperf/hyperf-skeleton) 项目的 `config/routes.php` ,下面是一些常用的用法示例。
|
||||
|
||||
```php
|
||||
<?php
|
||||
use Hyperf\HttpServer\Router\Router;
|
||||
@ -36,10 +38,19 @@ Router::addRoute(['GET', 'POST', 'HEAD'], '/multi', [\App\Controller\IndexContro
|
||||
`Hyperf` 提供了极其强大和方便灵活的 [注解](zh-cn/annotation.md) 功能,在路由的定义上也毫无疑问地提供了注解定义的方式,Hyperf 提供了 `@Controller` 和 `@AutoController` 两种注解来定义一个 `Controller`,此处仅做简单的说明,更多细节请查阅 [路由](zh-cn/router.md) 章节。
|
||||
|
||||
### 通过 `@AutoController` 注解定义路由
|
||||
|
||||
`@AutoController` 为绝大多数简单的访问场景提供路由绑定支持,使用 `@AutoController` 时则 Hyperf 会自动解析所在类的所有 `public` 方法并提供 `GET` 和 `POST` 两种请求方式。
|
||||
|
||||
> 使用 `@AutoController` 注解时需 `use Hyperf\HttpServer\Annotation\AutoController;` 命名空间;
|
||||
|
||||
驼峰命名的控制器,会自动转化为蛇形路由,以下为控制器与实际路由的对应关系示例:
|
||||
|
||||
| 控制器 | 注解 | 访问路由 |
|
||||
| :--------------: | :-----------------------------: | :------------: |
|
||||
| MyDataController | @AutoController() | /my_data/index |
|
||||
| MydataController | @AutoController() | /mydata/index |
|
||||
| MyDataController | @AutoController(prefix="/data") | /data/index |
|
||||
|
||||
```php
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
@ -318,22 +329,22 @@ class IndexController
|
||||
|
||||
除上述提到的 `SwooleEvent::ON_REQUEST` 事件,框架还支持其他事件,所有事件名如下。
|
||||
|
||||
| 事件名 | 备注 |
|
||||
|:-----------------------------:|:-----------------------------------:|
|
||||
| SwooleEvent::ON_REQUEST | |
|
||||
| SwooleEvent::ON_START | 该事件在 `SWOOLE_BASE` 模式下无效 |
|
||||
| SwooleEvent::ON_WORKER_START | |
|
||||
| SwooleEvent::ON_WORKER_EXIT | |
|
||||
| SwooleEvent::ON_PIPE_MESSAGE | |
|
||||
| SwooleEvent::ON_RECEIVE | |
|
||||
| SwooleEvent::ON_CONNECT | |
|
||||
| SwooleEvent::ON_HAND_SHAKE | |
|
||||
| SwooleEvent::ON_OPEN | |
|
||||
| SwooleEvent::ON_MESSAGE | |
|
||||
| SwooleEvent::ON_CLOSE | |
|
||||
| SwooleEvent::ON_TASK | |
|
||||
| SwooleEvent::ON_FINISH | |
|
||||
| SwooleEvent::ON_SHUTDOWN | |
|
||||
| SwooleEvent::ON_PACKET | |
|
||||
| SwooleEvent::ON_MANAGER_START | |
|
||||
| SwooleEvent::ON_MANAGER_STOP | |
|
||||
| 事件名 | 备注 |
|
||||
| :---------------------------: | :-------------------------------: |
|
||||
| SwooleEvent::ON_REQUEST | |
|
||||
| SwooleEvent::ON_START | 该事件在 `SWOOLE_BASE` 模式下无效 |
|
||||
| SwooleEvent::ON_WORKER_START | |
|
||||
| SwooleEvent::ON_WORKER_EXIT | |
|
||||
| SwooleEvent::ON_PIPE_MESSAGE | |
|
||||
| SwooleEvent::ON_RECEIVE | |
|
||||
| SwooleEvent::ON_CONNECT | |
|
||||
| SwooleEvent::ON_HAND_SHAKE | |
|
||||
| SwooleEvent::ON_OPEN | |
|
||||
| SwooleEvent::ON_MESSAGE | |
|
||||
| SwooleEvent::ON_CLOSE | |
|
||||
| SwooleEvent::ON_TASK | |
|
||||
| SwooleEvent::ON_FINISH | |
|
||||
| SwooleEvent::ON_SHUTDOWN | |
|
||||
| SwooleEvent::ON_PACKET | |
|
||||
| SwooleEvent::ON_MANAGER_START | |
|
||||
| SwooleEvent::ON_MANAGER_STOP | |
|
||||
|
@ -140,4 +140,18 @@ Fatal error: Uncaught PhpParser\Error: Syntax error, unexpected T_STRING on line
|
||||
可以执行脚本 `composer analyse`,对项目进行静态检测,便可以找到出现问题的代码段。
|
||||
|
||||
此问题通常是由于 [zircote/swagger](https://github.com/zircote/swagger-php) 的 3.0.5 版本更新导致, 详情请见 [#834](https://github.com/zircote/swagger-php/issues/834) 。
|
||||
如果安装了 [hyperf/swagger](https://github.com/hyperf/swagger) 建议将 [zircote/swagger](https://github.com/zircote/swagger-php) 的版本锁定在 3.0.4
|
||||
如果安装了 [hyperf/swagger](https://github.com/hyperf/swagger) 建议将 [zircote/swagger](https://github.com/zircote/swagger-php) 的版本锁定在 3.0.4
|
||||
|
||||
## 内存限制太小导致项目无法运行
|
||||
|
||||
PHP 默认的 `memory_limit` 只有 `128M`,因为 `Hyperf` 使用了 `BetterReflection`,不使用扫描缓存时,会消耗大量内存,所以可能会出现内存不够的情况。
|
||||
|
||||
我们可以使用 `php -dmemory_limit=-1 bin/hyperf.php start` 运行, 或者修改 `php.ini` 配置文件
|
||||
|
||||
```
|
||||
# 查看 php.ini 配置文件位置
|
||||
php --ini
|
||||
|
||||
# 修改 memory_limit 配置
|
||||
memory_limit=-1
|
||||
```
|
||||
|
@ -90,6 +90,14 @@ Router::addGroup('/user/',function (){
|
||||
|
||||
> 使用 `@AutoController` 注解时需 `use Hyperf\HttpServer\Annotation\AutoController;` 命名空间;
|
||||
|
||||
驼峰命名的控制器,会自动转化为蛇形路由,以下为控制器与实际路由的对应关系示例:
|
||||
|
||||
| 控制器 | 注解 | 访问路由 |
|
||||
| :--------------: | :-----------------------------: | :------------: |
|
||||
| MyDataController | @AutoController() | /my_data/index |
|
||||
| MydataController | @AutoController() | /mydata/index |
|
||||
| MyDataController | @AutoController(prefix="/data") | /data/index |
|
||||
|
||||
```php
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
@ -39,6 +39,44 @@ class Post extends Model
|
||||
}
|
||||
```
|
||||
## 配置
|
||||
|
||||
### 配置文件
|
||||
|
||||
生成配置文件
|
||||
|
||||
```
|
||||
php bin/hyperf.php vendor:publish hyperf/scout
|
||||
```
|
||||
|
||||
配置文件
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
'default' => env('SCOUT_ENGINE', 'elasticsearch'),
|
||||
'chunk' => [
|
||||
'searchable' => 500,
|
||||
'unsearchable' => 500,
|
||||
],
|
||||
'prefix' => env('SCOUT_PREFIX', ''),
|
||||
'soft_delete' => false,
|
||||
'concurrency' => 100,
|
||||
'engine' => [
|
||||
'elasticsearch' => [
|
||||
'driver' => Hyperf\Scout\Provider\ElasticsearchProvider::class,
|
||||
// 如果 index 设置为 null,则每个模型会对应一个索引,反之每个模型对应一个类型
|
||||
'index' => null,
|
||||
'hosts' => [
|
||||
env('ELASTICSEARCH_HOST', 'http://127.0.0.1:9200'),
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
```
|
||||
### 配置模型索引
|
||||
|
||||
每个模型与给定的搜索「索引」同步,这个「索引」包含该模型的所有可搜索记录。换句话说,你可以把每一个「索引」设想为一张 MySQL 数据表。默认情况下,每个模型都会被持久化到与模型的「表」名(通常是模型名称的复数形式)相匹配的索引。你也可以通过覆盖模型上的 `searchableAs` 方法来自定义模型的索引:
|
||||
@ -66,6 +104,7 @@ class Post extends Model
|
||||
}
|
||||
|
||||
<a name="configuring-searchable-data"></a>
|
||||
|
||||
### 配置可搜索的数据
|
||||
|
||||
默认情况下,「索引」会从模型的 `toArray` 方法中读取数据来做持久化。如果要自定义同步到搜索索引的数据,可以覆盖模型上的 `toSearchableArray` 方法:
|
||||
|
@ -381,15 +381,15 @@ if ($errors->has('foo')) {
|
||||
|
||||
##### alpha
|
||||
|
||||
验证字段必须是字母。
|
||||
验证字段必须是字母(包含中文)。
|
||||
|
||||
##### alpha_dash
|
||||
|
||||
验证字段可以包含字母和数字,以及破折号和下划线。
|
||||
验证字段可以包含字母(包含中文)和数字,以及破折号和下划线。
|
||||
|
||||
##### alpha_num
|
||||
|
||||
验证字段必须是字母或数字。
|
||||
验证字段必须是字母(包含中文)或数字。
|
||||
|
||||
##### array
|
||||
|
||||
|
@ -2,13 +2,13 @@
|
||||
|
||||
> 基于 laravel blade 模板引擎改写, 支持原始 blade 模板引擎的语法.
|
||||
|
||||
```
|
||||
```bash
|
||||
composer require hyperf/view-engine
|
||||
```
|
||||
|
||||
## 生成配置
|
||||
|
||||
```
|
||||
```bash
|
||||
php bin/hyperf.php vendor:publish hyperf/view-engine
|
||||
```
|
||||
|
||||
@ -109,7 +109,7 @@ return [
|
||||
@yield('content', 'Hyperf')
|
||||
```
|
||||
|
||||
`Blade` 视图可以用 `Hyperf\\ViewEngine\\view` 辅助函数返回:
|
||||
`Blade` 视图可以用 `Hyperf\ViewEngine\view` 辅助函数返回:
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -124,7 +124,7 @@ use function Hyperf\ViewEngine\view;
|
||||
/**
|
||||
* @AutoController(prefix="view")
|
||||
*/
|
||||
class ViewController extends Controller
|
||||
class ViewController extends AbstractController
|
||||
{
|
||||
public function child()
|
||||
{
|
||||
@ -792,7 +792,7 @@ class ConfigProvider
|
||||
|
||||
#### 组件自动加载
|
||||
|
||||
默认情况下,`App\View\Component\\` 及 `components.` 下的组件会自动注册。你也可以通过配置文件修改这个配置:
|
||||
默认情况下,`App\View\Component\` 及 `components.` 下的组件会自动注册。你也可以通过配置文件修改这个配置:
|
||||
|
||||
> config/autoload/view.php
|
||||
|
||||
|
@ -10,7 +10,13 @@ composer require hyperf/view
|
||||
|
||||
## 配置
|
||||
|
||||
View 组件的配置文件位于 `config/autoload/view.php`,若配置文件不存在可自行创建,以下为相关配置的说明:
|
||||
View 组件的配置文件位于 `config/autoload/view.php`,若配置文件不存在可执行如下命令生成配置文件
|
||||
|
||||
```bash
|
||||
php bin/hyperf.php vendor:publish hyperf/view
|
||||
```
|
||||
|
||||
以下为相关配置的说明:
|
||||
|
||||
| 配置 | 类型 | 默认值 | 备注 |
|
||||
|:-----------------:|:------:|:-------------------------------------:|:----------------:|
|
||||
|
@ -48,3 +48,4 @@ parameters:
|
||||
- '#InfluxDB\\Point constructor expects float\|null, string given#'
|
||||
- '#Call to an undefined method Hyperf\\Database\\Model\\Builder::unsearchable#'
|
||||
- '#trackerHookMalloc not found#'
|
||||
- '#method Phar\:\:buildFromIterator\(\) expects Iterator, Traversable given#'
|
||||
|
@ -40,6 +40,7 @@
|
||||
<directory suffix="Test.php">./src/model-cache/tests</directory>
|
||||
<directory suffix="Test.php">./src/nsq/tests</directory>
|
||||
<directory suffix="Test.php">./src/paginator/tests</directory>
|
||||
<directory suffix="Test.php">./src/phar/tests</directory>
|
||||
<directory suffix="Test.php">./src/pool/tests</directory>
|
||||
<directory suffix="Test.php">./src/process/tests</directory>
|
||||
<directory suffix="Test.php">./src/protocol/tests</directory>
|
||||
@ -92,6 +93,7 @@
|
||||
<directory suffix=".php">./src/model-cache/src</directory>
|
||||
<directory suffix=".php">./src/nsq/src</directory>
|
||||
<directory suffix=".php">./src/paginator/src</directory>
|
||||
<directory suffix=".php">./src/phar/src</directory>
|
||||
<directory suffix=".php">./src/redis/src</directory>
|
||||
<directory suffix=".php">./src/rpc/src</directory>
|
||||
<directory suffix=".php">./src/scout/src</directory>
|
||||
|
@ -16,15 +16,15 @@
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.2",
|
||||
"doctrine/instantiator": "^1.2.0",
|
||||
"hyperf/contract": "~2.1.0",
|
||||
"hyperf/utils": "~2.1.0",
|
||||
"hyperf/process": "~2.1.0",
|
||||
"hyperf/pool": "~2.1.0",
|
||||
"php-amqplib/php-amqplib": "^2.9.2",
|
||||
"psr/container": "^1.0",
|
||||
"psr/event-dispatcher": "^1.0",
|
||||
"psr/log": "^1.0",
|
||||
"php-amqplib/php-amqplib": "^2.7",
|
||||
"doctrine/instantiator": "^1.2.0"
|
||||
"psr/log": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"hyperf/di": "~2.1.0",
|
||||
|
@ -15,6 +15,7 @@ use Hyperf\Utils\Contracts\Arrayable;
|
||||
use Hyperf\Utils\Coroutine;
|
||||
use Hyperf\Utils\Str;
|
||||
use Psr\EventDispatcher\EventDispatcherInterface;
|
||||
use Swoole\ExitException;
|
||||
use Symfony\Component\Console\Command\Command as SymfonyCommand;
|
||||
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
@ -435,6 +436,8 @@ abstract class Command extends SymfonyCommand
|
||||
$this->eventDispatcher && $this->eventDispatcher->dispatch(new Event\BeforeHandle($this));
|
||||
call([$this, 'handle']);
|
||||
$this->eventDispatcher && $this->eventDispatcher->dispatch(new Event\AfterHandle($this));
|
||||
} catch (ExitException $exception) {
|
||||
// Do nothing.
|
||||
} catch (\Throwable $exception) {
|
||||
if (! $this->eventDispatcher) {
|
||||
throw $exception;
|
||||
|
@ -1298,7 +1298,7 @@ class Builder
|
||||
|
||||
[$name, $constraints] = Str::contains($name, ':')
|
||||
? $this->createSelectWithConstraint($name)
|
||||
: [$name, function () {
|
||||
: [$name, static function () {
|
||||
}];
|
||||
}
|
||||
|
||||
@ -1321,7 +1321,7 @@ class Builder
|
||||
*/
|
||||
protected function createSelectWithConstraint($name)
|
||||
{
|
||||
return [explode(':', $name)[0], function ($query) use ($name) {
|
||||
return [explode(':', $name)[0], static function ($query) use ($name) {
|
||||
$query->select(explode(',', explode(':', $name)[1]));
|
||||
}];
|
||||
}
|
||||
@ -1344,7 +1344,7 @@ class Builder
|
||||
$progress[] = $segment;
|
||||
|
||||
if (! isset($results[$last = implode('.', $progress)])) {
|
||||
$results[$last] = function () {
|
||||
$results[$last] = static function () {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -153,7 +153,7 @@ class CoreMiddleware implements CoreMiddlewareInterface
|
||||
} else {
|
||||
[$controller, $action] = $this->prepareHandler($dispatched->handler->callback);
|
||||
$controllerInstance = $this->container->get($controller);
|
||||
if (! method_exists($controller, $action)) {
|
||||
if (! method_exists($controllerInstance, $action)) {
|
||||
// Route found, but the handler does not exist.
|
||||
throw new ServerErrorHttpException('Method of class does not exist.');
|
||||
}
|
||||
|
@ -11,12 +11,14 @@ declare(strict_types=1);
|
||||
*/
|
||||
namespace HyperfTest\HttpServer;
|
||||
|
||||
use FastRoute\Dispatcher;
|
||||
use Hyperf\Contract\NormalizerInterface;
|
||||
use Hyperf\Di\ClosureDefinitionCollector;
|
||||
use Hyperf\Di\ClosureDefinitionCollectorInterface;
|
||||
use Hyperf\Di\MethodDefinitionCollector;
|
||||
use Hyperf\Di\MethodDefinitionCollectorInterface;
|
||||
use Hyperf\Dispatcher\HttpRequestHandler;
|
||||
use Hyperf\HttpMessage\Exception\ServerErrorHttpException;
|
||||
use Hyperf\HttpMessage\Server\Request;
|
||||
use Hyperf\HttpMessage\Stream\SwooleStream;
|
||||
use Hyperf\HttpMessage\Uri\Uri;
|
||||
@ -30,6 +32,7 @@ use Hyperf\Utils\Contracts\Jsonable;
|
||||
use Hyperf\Utils\Serializer\SimpleNormalizer;
|
||||
use HyperfTest\HttpServer\Stub\CoreMiddlewareStub;
|
||||
use HyperfTest\HttpServer\Stub\DemoController;
|
||||
use HyperfTest\HttpServer\Stub\FooController;
|
||||
use HyperfTest\HttpServer\Stub\SetHeaderMiddleware;
|
||||
use Mockery;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
@ -183,6 +186,37 @@ class CoreMiddlewareTest extends TestCase
|
||||
$response = $handler->handle($request);
|
||||
}
|
||||
|
||||
public function testHandleFound()
|
||||
{
|
||||
$container = $this->getContainer();
|
||||
$container->shouldReceive('get')->with(DemoController::class)->andReturn(new DemoController());
|
||||
$middleware = new CoreMiddleware($container, 'http');
|
||||
$ref = new \ReflectionClass($middleware);
|
||||
$method = $ref->getMethod('handleFound');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$handler = new Handler([DemoController::class, 'demo'], '/');
|
||||
$dispatched = new Dispatched([Dispatcher::FOUND, $handler, []]);
|
||||
$res = $method->invokeArgs($middleware, [$dispatched, Mockery::mock(ServerRequestInterface::class)]);
|
||||
$this->assertSame('Hello World.', $res);
|
||||
}
|
||||
|
||||
public function testHandleFoundWithNamespace()
|
||||
{
|
||||
$container = $this->getContainer();
|
||||
$container->shouldReceive('get')->with(DemoController::class)->andReturn(new FooController());
|
||||
$middleware = new CoreMiddleware($container, 'http');
|
||||
$ref = new \ReflectionClass($middleware);
|
||||
$method = $ref->getMethod('handleFound');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$this->expectException(ServerErrorHttpException::class);
|
||||
$this->expectExceptionMessage('Method of class does not exist.');
|
||||
$handler = new Handler([DemoController::class, 'demo'], '/');
|
||||
$dispatched = new Dispatched([Dispatcher::FOUND, $handler, []]);
|
||||
$method->invokeArgs($middleware, [$dispatched, Mockery::mock(ServerRequestInterface::class)]);
|
||||
}
|
||||
|
||||
protected function getContainer()
|
||||
{
|
||||
$container = Mockery::mock(ContainerInterface::class);
|
||||
|
@ -26,4 +26,9 @@ class DemoController
|
||||
{
|
||||
return $this->__return($id, $name, $params);
|
||||
}
|
||||
|
||||
public function demo()
|
||||
{
|
||||
return 'Hello World.';
|
||||
}
|
||||
}
|
||||
|
16
src/http-server/tests/Stub/FooController.php
Normal file
16
src/http-server/tests/Stub/FooController.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace HyperfTest\HttpServer\Stub;
|
||||
|
||||
class FooController
|
||||
{
|
||||
}
|
@ -29,7 +29,7 @@ class InvalidCacheManager
|
||||
|
||||
public function delete(): void
|
||||
{
|
||||
foreach ($this->models as $model) {
|
||||
while ($model = array_pop($this->models)) {
|
||||
$model->deleteCache();
|
||||
}
|
||||
}
|
||||
|
@ -93,6 +93,20 @@ class ManagerTest extends TestCase
|
||||
$this->assertSame(100, $manager->getCacheTTL($model, $handler));
|
||||
}
|
||||
|
||||
public function testInvalidCacheManager()
|
||||
{
|
||||
parallel([static function () {
|
||||
$manager = ModelCache\InvalidCacheManager::instance();
|
||||
$model = Mockery::mock(ModelCache\CacheableInterface::class);
|
||||
$model->shouldReceive('deleteCache')->once()->andReturn(true);
|
||||
$manager->push($model);
|
||||
$manager->delete();
|
||||
$manager->delete();
|
||||
}]);
|
||||
|
||||
$this->assertInstanceOf(ModelCache\InvalidCacheManager::class, ModelCache\InvalidCacheManager::instance());
|
||||
}
|
||||
|
||||
protected function getConfig(): array
|
||||
{
|
||||
return [
|
||||
|
@ -22,8 +22,10 @@ use Hyperf\Nacos\Constants;
|
||||
use Hyperf\Nacos\Exception\RuntimeException;
|
||||
use Hyperf\Nacos\Instance;
|
||||
use Hyperf\Nacos\Service;
|
||||
use Hyperf\Server\Event\CoroutineServerStart;
|
||||
use Hyperf\Server\Event\MainCoroutineServerStart;
|
||||
use Hyperf\Utils\Arr;
|
||||
use Hyperf\Utils\Coordinator\CoordinatorManager;
|
||||
use Hyperf\Utils\Coroutine;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
class MainWorkerStartListener implements ListenerInterface
|
||||
@ -48,7 +50,7 @@ class MainWorkerStartListener implements ListenerInterface
|
||||
{
|
||||
return [
|
||||
MainWorkerStart::class,
|
||||
CoroutineServerStart::class,
|
||||
MainCoroutineServerStart::class,
|
||||
];
|
||||
}
|
||||
|
||||
@ -79,19 +81,49 @@ class MainWorkerStartListener implements ListenerInterface
|
||||
}
|
||||
$this->logger->info('nacos register instance success.', compact('instance'));
|
||||
|
||||
$client = $this->container->get(Client::class);
|
||||
$config = $this->container->get(ConfigInterface::class);
|
||||
$appendNode = $config->get('nacos.config_append_node');
|
||||
$this->refreshConfig();
|
||||
|
||||
foreach ($client->pull() as $key => $conf) {
|
||||
$configKey = $appendNode ? $appendNode . '.' . $key : $key;
|
||||
if (is_array($conf) && $config->get('nacos.config_merge_mode') == Constants::CONFIG_MERGE_APPEND) {
|
||||
$conf = Arr::merge($config->get($configKey, []), $conf);
|
||||
}
|
||||
$config->set($configKey, $conf);
|
||||
if ($event instanceof MainCoroutineServerStart) {
|
||||
$interval = (int) $config->get('nacos.config_reload_interval', 3);
|
||||
Coroutine::create(function () use ($interval) {
|
||||
sleep($interval);
|
||||
retry(INF, function () use ($interval) {
|
||||
$prevConfig = [];
|
||||
while (true) {
|
||||
$coordinator = CoordinatorManager::until(\Hyperf\Utils\Coordinator\Constants::WORKER_EXIT);
|
||||
$workerExited = $coordinator->yield($interval);
|
||||
if ($workerExited) {
|
||||
break;
|
||||
}
|
||||
$prevConfig = $this->refreshConfig($prevConfig);
|
||||
}
|
||||
}, $interval * 1000);
|
||||
});
|
||||
}
|
||||
} catch (\Throwable $exception) {
|
||||
$this->logger->critical((string) $exception);
|
||||
}
|
||||
}
|
||||
|
||||
protected function refreshConfig(array $prevConfig = []): array
|
||||
{
|
||||
$client = $this->container->get(Client::class);
|
||||
$config = $this->container->get(ConfigInterface::class);
|
||||
$appendNode = $config->get('nacos.config_append_node');
|
||||
|
||||
$result = $client->pull();
|
||||
if ($result === $prevConfig) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
foreach ($result as $key => $conf) {
|
||||
$configKey = $appendNode ? $appendNode . '.' . $key : $key;
|
||||
if (is_array($conf) && $config->get('nacos.config_merge_mode') == Constants::CONFIG_MERGE_APPEND) {
|
||||
$conf = Arr::merge($config->get($configKey, []), $conf);
|
||||
}
|
||||
$config->set($configKey, $conf);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
2
src/phar/.gitattributes
vendored
Normal file
2
src/phar/.gitattributes
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/tests export-ignore
|
||||
/.github export-ignore
|
25
src/phar/.github/workflows/release.yml
vendored
Normal file
25
src/phar/.github/workflows/release.yml
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
on:
|
||||
push:
|
||||
# Sequence of patterns matched against refs/tags
|
||||
tags:
|
||||
- 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10
|
||||
|
||||
name: Release
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: Release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Create Release
|
||||
id: create_release
|
||||
uses: actions/create-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ github.ref }}
|
||||
release_name: Release ${{ github.ref }}
|
||||
draft: false
|
||||
prerelease: false
|
21
src/phar/LICENSE
Normal file
21
src/phar/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) Hyperf
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
55
src/phar/composer.json
Normal file
55
src/phar/composer.json
Normal file
@ -0,0 +1,55 @@
|
||||
{
|
||||
"name": "hyperf/phar",
|
||||
"description": "A component that supports pack Hyperf project as a Phar stand-alone package.",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"php",
|
||||
"swoole",
|
||||
"hyperf",
|
||||
"phar"
|
||||
],
|
||||
"homepage": "https://hyperf.io",
|
||||
"support": {
|
||||
"docs": "https://hyperf.wiki",
|
||||
"issues": "https://github.com/hyperf/hyperf/issues",
|
||||
"pull-request": "https://github.com/hyperf/hyperf/pulls",
|
||||
"source": "https://github.com/hyperf/hyperf"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Hyperf\\Phar\\": "src/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"HyperfTest\\Phar\\": "tests/"
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.2",
|
||||
"ext-json": "*",
|
||||
"hyperf/command": "~2.0.0",
|
||||
"hyperf/contract": "~2.0.0",
|
||||
"nikic/php-parser": "^4.1",
|
||||
"psr/container": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "^2.14",
|
||||
"mockery/mockery": "^1.0",
|
||||
"phpstan/phpstan": "^0.12",
|
||||
"phpunit/phpunit": ">=7.0"
|
||||
},
|
||||
"config": {
|
||||
"sort-packages": true
|
||||
},
|
||||
"scripts": {
|
||||
"test": "phpunit -c phpunit.xml --colors=always",
|
||||
"analyse": "phpstan analyse --memory-limit 1024M -l 0 ./src",
|
||||
"cs-fix": "php-cs-fixer fix $1"
|
||||
},
|
||||
"extra": {
|
||||
"hyperf": {
|
||||
"config": "Hyperf\\Phar\\ConfigProvider"
|
||||
}
|
||||
}
|
||||
}
|
32
src/phar/src/Ast/Ast.php
Normal file
32
src/phar/src/Ast/Ast.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Phar\Ast;
|
||||
|
||||
use PhpParser\NodeTraverser;
|
||||
use PhpParser\ParserFactory;
|
||||
use PhpParser\PrettyPrinter\Standard;
|
||||
|
||||
class Ast
|
||||
{
|
||||
public static function parse(string $code, array $visitors): string
|
||||
{
|
||||
$parser = (new ParserFactory())->create(ParserFactory::ONLY_PHP7);
|
||||
$printer = new Standard();
|
||||
$traverser = new NodeTraverser();
|
||||
foreach ($visitors as $visitor) {
|
||||
$traverser->addVisitor($visitor);
|
||||
}
|
||||
$stmts = $parser->parse($code);
|
||||
$stmts = $traverser->traverse($stmts);
|
||||
return $printer->prettyPrintFile($stmts);
|
||||
}
|
||||
}
|
36
src/phar/src/Ast/Visitor/RewriteConfigVisitor.php
Normal file
36
src/phar/src/Ast/Visitor/RewriteConfigVisitor.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Phar\Ast\Visitor;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\NodeVisitorAbstract;
|
||||
|
||||
class RewriteConfigVisitor extends NodeVisitorAbstract
|
||||
{
|
||||
public function leaveNode(Node $node)
|
||||
{
|
||||
if ($node instanceof Node\Stmt\Return_) {
|
||||
if (! $node->expr instanceof Node\Expr\Array_) {
|
||||
return $node;
|
||||
}
|
||||
foreach ($node->expr->items as $item) {
|
||||
if (! $item instanceof Node\Expr\ArrayItem) {
|
||||
continue;
|
||||
}
|
||||
if ($item->key instanceof Node\Scalar\String_ && strtolower($item->key->value) == 'scan_cacheable') {
|
||||
$item->value = new Node\Expr\ConstFetch(new Node\Name('true'));
|
||||
}
|
||||
}
|
||||
}
|
||||
return $node;
|
||||
}
|
||||
}
|
91
src/phar/src/BuildCommand.php
Normal file
91
src/phar/src/BuildCommand.php
Normal file
@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Phar;
|
||||
|
||||
use Hyperf\Command\Command as HyperfCommand;
|
||||
use InvalidArgumentException;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use RuntimeException;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use UnexpectedValueException;
|
||||
|
||||
class BuildCommand extends HyperfCommand
|
||||
{
|
||||
/**
|
||||
* @var ContainerInterface
|
||||
*/
|
||||
protected $container;
|
||||
|
||||
public function __construct(ContainerInterface $container)
|
||||
{
|
||||
parent::__construct('phar:build');
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
public function configure()
|
||||
{
|
||||
$this->setDescription('Pack your project into a Phar package.')
|
||||
->addOption('name', '', InputOption::VALUE_OPTIONAL, 'This is the name of the Phar package, and if it is not passed in, the project name is used by default', null)
|
||||
->addOption('bin', 'b', InputOption::VALUE_OPTIONAL, 'The script path to execute by default.', 'bin/hyperf.php')
|
||||
->addOption('path', 'p', InputOption::VALUE_OPTIONAL, 'Project root path, default BASE_PATH.', null);
|
||||
}
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$this->assertWritable();
|
||||
$name = $this->input->getOption('name');
|
||||
$bin = $this->input->getOption('bin');
|
||||
$path = $this->input->getOption('path');
|
||||
if (empty($path)) {
|
||||
$path = BASE_PATH;
|
||||
}
|
||||
$builder = $this->getPharBuilder($path);
|
||||
if (! empty($bin)) {
|
||||
$builder->setMain($bin);
|
||||
}
|
||||
if (! empty($name)) {
|
||||
$builder->setTarget($name);
|
||||
}
|
||||
$builder->build();
|
||||
}
|
||||
|
||||
/**
|
||||
* check readonly.
|
||||
*/
|
||||
public function assertWritable()
|
||||
{
|
||||
if (ini_get('phar.readonly') === '1') {
|
||||
throw new UnexpectedValueException('Your configuration disabled writing phar files (phar.readonly = On), please update your configuration');
|
||||
}
|
||||
}
|
||||
|
||||
public function getPharBuilder(string $path, ?string $version = null): PharBuilder
|
||||
{
|
||||
if ($version !== null) {
|
||||
$path .= ':' . $version;
|
||||
}
|
||||
|
||||
if (is_dir($path)) {
|
||||
$path = rtrim($path, '/') . '/composer.json';
|
||||
}
|
||||
if (! is_file($path)) {
|
||||
throw new InvalidArgumentException(sprintf('The given path %s is not a readable file', $path));
|
||||
}
|
||||
$pharBuilder = new PharBuilder($path, $this->container->get(LoggerInterface::class));
|
||||
|
||||
$vendorPath = $pharBuilder->getPackage()->getVendorAbsolutePath();
|
||||
if (! is_dir($vendorPath)) {
|
||||
throw new RuntimeException('The project has not been initialized, please manually execute the command `composer install` to install the dependencies');
|
||||
}
|
||||
return $pharBuilder;
|
||||
}
|
||||
}
|
95
src/phar/src/Bundle.php
Normal file
95
src/phar/src/Bundle.php
Normal file
@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Phar;
|
||||
|
||||
use ArrayIterator;
|
||||
use IteratorAggregate;
|
||||
use SplFileInfo;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use Traversable;
|
||||
|
||||
class Bundle implements IteratorAggregate
|
||||
{
|
||||
/**
|
||||
* @var Finder[]|string[]
|
||||
*/
|
||||
private $resources = [];
|
||||
|
||||
/**
|
||||
* Add a file to the resource bundle.
|
||||
* @return $this
|
||||
*/
|
||||
public function addFile(string $file)
|
||||
{
|
||||
$this->resources[] = $file;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $dirs
|
||||
* @return $this
|
||||
*/
|
||||
public function addDirs(array $dirs)
|
||||
{
|
||||
return $this->addFinder((new Finder())->files()->ignoreVCS(true)->in($dirs));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a directory package to a resource package.
|
||||
* @return $this
|
||||
*/
|
||||
public function addFinder(Finder $dir)
|
||||
{
|
||||
$this->resources[] = $dir;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the file exists in the resource bundle.
|
||||
*/
|
||||
public function checkContains(string $resource): bool
|
||||
{
|
||||
foreach ($this->resources as $containedResource) {
|
||||
if ($containedResource instanceof Finder && $this->directoryContains($containedResource, $resource)) {
|
||||
return true;
|
||||
}
|
||||
if (is_string($containedResource) && $containedResource === $resource) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator for a list of resources.
|
||||
*/
|
||||
public function getIterator(): Traversable
|
||||
{
|
||||
return new ArrayIterator($this->resources);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the file exists in the folder resource bundle.
|
||||
*/
|
||||
private function directoryContains(Finder $dir, string $resource): bool
|
||||
{
|
||||
$resourceStrLength = strlen($resource);
|
||||
foreach ($dir as $containedResource) {
|
||||
/* @var $containedResource SplFileInfo */
|
||||
if (substr($containedResource->getRealPath(), 0, $resourceStrLength) == $resource) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
29
src/phar/src/ConfigProvider.php
Normal file
29
src/phar/src/ConfigProvider.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Phar;
|
||||
|
||||
use Hyperf\Framework\Logger\StdoutLogger;
|
||||
|
||||
class ConfigProvider
|
||||
{
|
||||
public function __invoke(): array
|
||||
{
|
||||
return [
|
||||
'dependencies' => [
|
||||
LoggerInterface::class => StdoutLogger::class,
|
||||
],
|
||||
'commands' => [
|
||||
BuildCommand::class,
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
16
src/phar/src/LoggerInterface.php
Normal file
16
src/phar/src/LoggerInterface.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Phar;
|
||||
|
||||
interface LoggerInterface extends \Psr\Log\LoggerInterface
|
||||
{
|
||||
}
|
115
src/phar/src/Package.php
Normal file
115
src/phar/src/Package.php
Normal file
@ -0,0 +1,115 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Phar;
|
||||
|
||||
use Symfony\Component\Finder\Finder;
|
||||
|
||||
class Package
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $package;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $directory;
|
||||
|
||||
public function __construct(array $package, string $directory)
|
||||
{
|
||||
$this->package = $package;
|
||||
$this->directory = rtrim($directory, '/') . '/';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get full package name.
|
||||
*/
|
||||
public function getName(): ?string
|
||||
{
|
||||
return $this->package['name'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the short package name
|
||||
* If not, the pathname is used as the package name.
|
||||
*/
|
||||
public function getShortName(): string
|
||||
{
|
||||
$name = $this->getName();
|
||||
if ($name === null) {
|
||||
$name = realpath($this->getDirectory());
|
||||
if ($name === false) {
|
||||
$name = $this->getDirectory();
|
||||
}
|
||||
}
|
||||
return basename($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the relative address of the vendor directory, which supports custom addresses in composer.json.
|
||||
*/
|
||||
public function getVendorPath(): string
|
||||
{
|
||||
$vendor = 'vendor';
|
||||
if (isset($this->package['config']['vendor-dir'])) {
|
||||
$vendor = $this->package['config']['vendor-dir'];
|
||||
}
|
||||
return $vendor . '/';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the absolute address of the vendor directory.
|
||||
*/
|
||||
public function getVendorAbsolutePath(): string
|
||||
{
|
||||
return $this->getDirectory() . $this->getVendorPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get package directory.
|
||||
*/
|
||||
public function getDirectory(): string
|
||||
{
|
||||
return $this->directory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get resource bundle object.
|
||||
*/
|
||||
public function bundle(Finder $finder = null): Bundle
|
||||
{
|
||||
$bundle = new Bundle();
|
||||
$dir = $this->getDirectory();
|
||||
$vendorPath = $this->getVendorPath();
|
||||
if (empty($this->package['autoload']) && ! is_dir($dir . $vendorPath)) {
|
||||
return $bundle;
|
||||
}
|
||||
if ($finder == null) {
|
||||
$finder = Finder::create()
|
||||
->files()
|
||||
->ignoreVCS(true)
|
||||
->exclude(rtrim($vendorPath, '/'))
|
||||
->notPath('/^composer\.phar/')
|
||||
->in($dir);
|
||||
}
|
||||
return $bundle->addFinder($finder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the executable file path, and the directory address where the Phar package will run.
|
||||
*/
|
||||
public function getBins(): array
|
||||
{
|
||||
return $this->package['bin'] ?? [];
|
||||
}
|
||||
}
|
281
src/phar/src/PharBuilder.php
Normal file
281
src/phar/src/PharBuilder.php
Normal file
@ -0,0 +1,281 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Phar;
|
||||
|
||||
use FilesystemIterator;
|
||||
use GlobIterator;
|
||||
use Hyperf\Phar\Ast\Ast;
|
||||
use Hyperf\Phar\Ast\Visitor\RewriteConfigVisitor;
|
||||
use InvalidArgumentException;
|
||||
use Phar;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use RuntimeException;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use UnexpectedValueException;
|
||||
|
||||
class PharBuilder
|
||||
{
|
||||
/**
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
protected $logger;
|
||||
|
||||
/**
|
||||
* @var Package
|
||||
*/
|
||||
private $package;
|
||||
|
||||
/**
|
||||
* @var null|string|TargetPhar
|
||||
*/
|
||||
private $target;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $main;
|
||||
|
||||
public function __construct(string $path, LoggerInterface $logger)
|
||||
{
|
||||
$this->logger = $logger;
|
||||
$this->package = new Package($this->loadJson($path), dirname(realpath($path)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Phar package name.
|
||||
*/
|
||||
public function getTarget(): string
|
||||
{
|
||||
if ($this->target === null) {
|
||||
$this->target = $this->package->getShortName() . '.phar';
|
||||
}
|
||||
return (string) $this->target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Phar package name.
|
||||
* @param string|TargetPhar $target
|
||||
* @return $this
|
||||
*/
|
||||
public function setTarget($target)
|
||||
{
|
||||
if (is_dir($target)) {
|
||||
$this->target = null;
|
||||
$target = rtrim($target, '/') . '/' . $this->getTarget();
|
||||
}
|
||||
$this->target = $target;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default run script path.
|
||||
*/
|
||||
public function getMain(): string
|
||||
{
|
||||
if ($this->main === null) {
|
||||
foreach ($this->package->getBins() as $path) {
|
||||
if (! file_exists($this->package->getDirectory() . $path)) {
|
||||
throw new UnexpectedValueException('Bin file "' . $path . '" does not exist');
|
||||
}
|
||||
$this->main = $path;
|
||||
break;
|
||||
}
|
||||
// Use the default hyperf bootstrap file as default.
|
||||
if ($this->main == null) {
|
||||
return 'bin/hyperf.php';
|
||||
}
|
||||
}
|
||||
return $this->main;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default startup file.
|
||||
* @return $this
|
||||
*/
|
||||
public function setMain(string $main)
|
||||
{
|
||||
$this->main = $main;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get package object.
|
||||
*/
|
||||
public function getPackage(): Package
|
||||
{
|
||||
return $this->package;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of all dependent packages.
|
||||
* @return Package[]
|
||||
*/
|
||||
public function getPackagesDependencies(): array
|
||||
{
|
||||
$packages = [];
|
||||
|
||||
$vendorPath = $this->package->getVendorAbsolutePath();
|
||||
|
||||
// Gets all installed dependency packages
|
||||
if (is_file($vendorPath . 'composer/installed.json')) {
|
||||
$installed = $this->loadJson($vendorPath . 'composer/installed.json');
|
||||
$installedPackages = $installed;
|
||||
// Adapte Composer 2.0
|
||||
if (isset($installed['packages'])) {
|
||||
$installedPackages = $installed['packages'];
|
||||
}
|
||||
// Package all of these dependent components into the packages
|
||||
foreach ($installedPackages as $package) {
|
||||
$dir = $package['name'] . '/';
|
||||
if (isset($package['target-dir'])) {
|
||||
$dir .= trim($package['target-dir'], '/') . '/';
|
||||
}
|
||||
|
||||
$dir = $vendorPath . $dir;
|
||||
$packages[] = new Package($package, $dir);
|
||||
}
|
||||
}
|
||||
return $packages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the relative path relative to the resource bundle.
|
||||
*/
|
||||
public function getPathLocalToBase(string $path): ?string
|
||||
{
|
||||
$root = $this->package->getDirectory();
|
||||
if (strpos($path, $root) !== 0) {
|
||||
throw new UnexpectedValueException('Path "' . $path . '" is not within base project path "' . $root . '"');
|
||||
}
|
||||
return substr($path, strlen($root)) ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile the code into the Phar file.
|
||||
*/
|
||||
public function build()
|
||||
{
|
||||
$this->logger->info('Creating phar <info>' . $this->getTarget() . '</info>');
|
||||
$time = microtime(true);
|
||||
|
||||
$vendorPath = $this->package->getVendorAbsolutePath();
|
||||
if (! is_dir($vendorPath)) {
|
||||
throw new RuntimeException(sprintf('Directory %s not properly installed, did you run "composer install" ?', $vendorPath));
|
||||
}
|
||||
|
||||
// Get file path which could be written for phar.
|
||||
$target = $this->getTarget();
|
||||
do {
|
||||
$tmp = $target . '.' . mt_rand() . '.phar';
|
||||
} while (file_exists($tmp));
|
||||
|
||||
$targetPhar = new TargetPhar(new Phar($tmp), $this);
|
||||
$this->logger->info('Adding main package "' . $this->package->getName() . '"');
|
||||
$finder = Finder::create()
|
||||
->files()
|
||||
->ignoreVCS(true)
|
||||
->exclude(rtrim($this->package->getVendorPath(), '/'))
|
||||
->exclude('runtime') //Ignore runtime dir
|
||||
->notPath('/^composer\.phar/')
|
||||
->notPath($target) //Ignore the phar package that exists in the project itself
|
||||
->in($this->package->getDirectory());
|
||||
$targetPhar->addBundle($this->package->bundle($finder));
|
||||
|
||||
// Force to turn on ScanCacheable.
|
||||
$this->enableScanCacheable($targetPhar);
|
||||
|
||||
// Load the Runtime folder separately
|
||||
if (is_dir($this->package->getDirectory() . 'runtime')) {
|
||||
$this->logger->info('Adding runtime container files');
|
||||
$finder = Finder::create()
|
||||
->files()
|
||||
->in($this->package->getDirectory() . 'runtime/container');
|
||||
$targetPhar->addBundle($this->package->bundle($finder));
|
||||
}
|
||||
|
||||
$this->logger->info('Adding composer base files');
|
||||
// Add composer autoload file.
|
||||
$targetPhar->addFile($vendorPath . 'autoload.php');
|
||||
|
||||
// Add composer autoload files.
|
||||
$targetPhar->buildFromIterator(new GlobIterator($vendorPath . 'composer/*.*', FilesystemIterator::KEY_AS_FILENAME));
|
||||
|
||||
// Add composer depenedencies.
|
||||
foreach ($this->getPackagesDependencies() as $package) {
|
||||
// Cannot package yourself.
|
||||
if (stripos($package->getDirectory(), 'vendor/hyperf/phar/') !== false) {
|
||||
continue;
|
||||
}
|
||||
$this->logger->info('Adding dependency "' . $package->getName() . '" from "' . $this->getPathLocalToBase($package->getDirectory()) . '"');
|
||||
$targetPhar->addBundle($package->bundle());
|
||||
}
|
||||
|
||||
$this->logger->info('Setting main/stub');
|
||||
|
||||
$main = $this->getMain();
|
||||
// Add the default stub.
|
||||
$targetPhar->setStub($targetPhar->createDefaultStub($main));
|
||||
$this->logger->info('Setting default stub <info>' . $main . '</info>.');
|
||||
|
||||
$targetPhar->stopBuffering();
|
||||
|
||||
if (file_exists($target)) {
|
||||
$this->logger->info('Overwriting existing file <info>' . $target . '</info> (' . $this->getSize($target) . ')');
|
||||
}
|
||||
|
||||
if (rename($tmp, $target) === false) {
|
||||
throw new UnexpectedValueException(sprintf('Unable to rename temporary phar archive to %s', $target));
|
||||
}
|
||||
|
||||
$time = max(microtime(true) - $time, 0);
|
||||
|
||||
$this->logger->info('');
|
||||
$this->logger->info(' <info>OK</info> - Creating <info>' . $this->getTarget() . '</info> (' . $this->getSize($this->getTarget()) . ') completed after ' . round($time, 1) . 's');
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the scan_cacheable configuration and force it to open.
|
||||
*/
|
||||
protected function enableScanCacheable(TargetPhar $targetPhar)
|
||||
{
|
||||
$configPath = 'config/config.php';
|
||||
$absPath = $this->package->getDirectory() . $configPath;
|
||||
if (! file_exists($absPath)) {
|
||||
return;
|
||||
}
|
||||
$code = file_get_contents($absPath);
|
||||
$code = Ast::parse($code, [new RewriteConfigVisitor()]);
|
||||
$targetPhar->addFromString($configPath, $code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the configuration.
|
||||
*/
|
||||
private function loadJson(string $path): array
|
||||
{
|
||||
$result = json_decode(file_get_contents($path), true);
|
||||
if ($result === null) {
|
||||
throw new InvalidArgumentException(sprintf('Unable to parse given path %s', $path), json_last_error());
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file size.
|
||||
*
|
||||
* @param PharBuilder|string $path
|
||||
*/
|
||||
private function getSize($path): string
|
||||
{
|
||||
return round(filesize((string) $path) / 1024, 1) . ' KiB';
|
||||
}
|
||||
}
|
108
src/phar/src/TargetPhar.php
Normal file
108
src/phar/src/TargetPhar.php
Normal file
@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Phar;
|
||||
|
||||
use Phar;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use Traversable;
|
||||
|
||||
class TargetPhar
|
||||
{
|
||||
/**
|
||||
* @var Phar
|
||||
*/
|
||||
private $phar;
|
||||
|
||||
/**
|
||||
* @var PharBuilder
|
||||
*/
|
||||
private $pharBuilder;
|
||||
|
||||
public function __construct(Phar $phar, PharBuilder $pharBuilder)
|
||||
{
|
||||
$phar->startBuffering();
|
||||
$this->phar = $phar;
|
||||
$this->pharBuilder = $pharBuilder;
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
$exploded = explode('/', $this->phar->getPath());
|
||||
return end($exploded);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start writing the Phar package.
|
||||
*/
|
||||
public function stopBuffering()
|
||||
{
|
||||
$this->phar->stopBuffering();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a resource bundle to the Phar package.
|
||||
*/
|
||||
public function addBundle(Bundle $bundle)
|
||||
{
|
||||
/** @var Finder|string $resource */
|
||||
foreach ($bundle as $resource) {
|
||||
if (is_string($resource)) {
|
||||
$this->addFile($resource);
|
||||
} else {
|
||||
$this->buildFromIterator($resource);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the file to the Phar package.
|
||||
*/
|
||||
public function addFile(string $filename): void
|
||||
{
|
||||
$this->phar->addFile($filename, $this->pharBuilder->getPathLocalToBase($filename));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add folder resources to the Phar package.
|
||||
*/
|
||||
public function buildFromIterator(Traversable $iterator): void
|
||||
{
|
||||
$this->phar->buildFromIterator($iterator, $this->pharBuilder->getPackage()->getDirectory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the default execution file.
|
||||
*/
|
||||
public function createDefaultStub(string $indexFile, string $webIndexFile = null): string
|
||||
{
|
||||
if ($webIndexFile != null) {
|
||||
return $this->phar->createDefaultStub($indexFile, $webIndexFile);
|
||||
}
|
||||
return $this->phar->createDefaultStub($indexFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default startup file.
|
||||
*/
|
||||
public function setStub(string $stub): void
|
||||
{
|
||||
$this->phar->setStub($stub);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a string to the Phar package.
|
||||
*/
|
||||
public function addFromString(string $local, string $contents): void
|
||||
{
|
||||
$this->phar->addFromString($local, $contents);
|
||||
}
|
||||
}
|
93
src/phar/tests/PackageTest.php
Normal file
93
src/phar/tests/PackageTest.php
Normal file
@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace HyperfTest\Phar;
|
||||
|
||||
use Hyperf\Phar\Package;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @coversNothing
|
||||
*/
|
||||
class PackageTest extends TestCase
|
||||
{
|
||||
public function testDefaults()
|
||||
{
|
||||
$package = new Package([], 'dirs/');
|
||||
|
||||
$this->assertEquals([], $package->getBins());
|
||||
$this->assertEquals('dirs/', $package->getDirectory());
|
||||
$this->assertEquals(null, $package->getName());
|
||||
$this->assertEquals('dirs', $package->getShortName());
|
||||
$this->assertEquals('vendor/', $package->getVendorPath());
|
||||
}
|
||||
|
||||
public function testPackage()
|
||||
{
|
||||
$package = new Package([
|
||||
'name' => 'hyperf/phar',
|
||||
'bin' => ['bin/hyperf.php', 'bin/phar.php'],
|
||||
'config' => [
|
||||
'vendor-dir' => 'src/vendors',
|
||||
],
|
||||
], 'dirs/');
|
||||
$this->assertEquals(['bin/hyperf.php', 'bin/phar.php'], $package->getBins());
|
||||
$this->assertEquals('hyperf/phar', $package->getName());
|
||||
$this->assertEquals('phar', $package->getShortName());
|
||||
$this->assertEquals('src/vendors/', $package->getVendorPath());
|
||||
}
|
||||
|
||||
public function testBundleWillContainComposerJsonButNotVendor()
|
||||
{
|
||||
$dir = realpath(__DIR__ . '/fixtures/03-project-with-phars') . '/';
|
||||
$package = new Package([
|
||||
'config' => [
|
||||
'vendor-dir' => 'vendors',
|
||||
],
|
||||
], $dir);
|
||||
$bundle = $package->bundle();
|
||||
|
||||
$this->assertTrue($bundle->checkContains($dir . 'composer.json'));
|
||||
$this->assertFalse($bundle->checkContains($dir . 'vendor/autoload.php'));
|
||||
$this->assertFalse($bundle->checkContains($dir . 'composer.phar'));
|
||||
$this->assertTrue($bundle->checkContains($dir . 'phar-composer.phar'));
|
||||
}
|
||||
|
||||
public function testBundleWillNotContainComposerPharInRoot()
|
||||
{
|
||||
$dir = realpath(__DIR__ . '/fixtures/03-project-with-phars') . '/';
|
||||
$package = new Package([
|
||||
'config' => [
|
||||
'vendor-dir' => 'vendors',
|
||||
],
|
||||
], $dir);
|
||||
$bundle = $package->bundle();
|
||||
|
||||
$this->assertFalse($bundle->checkContains($dir . 'composer.phar'));
|
||||
$this->assertTrue($bundle->checkContains($dir . 'phar-composer.phar'));
|
||||
}
|
||||
|
||||
public function testBundleWillContainComposerPharFromSrc()
|
||||
{
|
||||
$dir = realpath(__DIR__ . '/fixtures/04-project-with-phars-in-src') . '/';
|
||||
$package = new Package([
|
||||
'config' => [
|
||||
'vendor-dir' => 'vendors',
|
||||
],
|
||||
], $dir);
|
||||
$bundle = $package->bundle();
|
||||
|
||||
$this->assertTrue($bundle->checkContains($dir . 'composer.json'));
|
||||
$this->assertTrue($bundle->checkContains($dir . 'src/composer.phar'));
|
||||
$this->assertTrue($bundle->checkContains($dir . 'src/phar-composer.phar'));
|
||||
}
|
||||
}
|
74
src/phar/tests/VisitorTest.php
Normal file
74
src/phar/tests/VisitorTest.php
Normal file
@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace HyperfTest\Phar;
|
||||
|
||||
use Hyperf\Phar\Ast\Ast;
|
||||
use Hyperf\Phar\Ast\Visitor\RewriteConfigVisitor;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @coversNothing
|
||||
*/
|
||||
class VisitorTest extends TestCase
|
||||
{
|
||||
public function testRewriteConfig()
|
||||
{
|
||||
$code = "<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
use Hyperf\\Contract\\StdoutLoggerInterface;
|
||||
use Psr\\Log\\LogLevel;
|
||||
|
||||
return [
|
||||
'app_name' => env('APP_NAME', 'skeleton'),
|
||||
'app_env' => env('APP_ENV', 'dev'),
|
||||
'scan_cacheable' => env('SCAN_CACHEABLE', false),
|
||||
StdoutLoggerInterface::class => [
|
||||
'log_level' => [
|
||||
LogLevel::ALERT,
|
||||
LogLevel::CRITICAL,
|
||||
LogLevel::DEBUG,
|
||||
LogLevel::EMERGENCY,
|
||||
LogLevel::ERROR,
|
||||
LogLevel::INFO,
|
||||
LogLevel::NOTICE,
|
||||
LogLevel::WARNING,
|
||||
],
|
||||
],
|
||||
];
|
||||
";
|
||||
$code = Ast::parse($code, [new RewriteConfigVisitor()]);
|
||||
$this->assertSame("<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
use Hyperf\\Contract\\StdoutLoggerInterface;
|
||||
use Psr\\Log\\LogLevel;
|
||||
return ['app_name' => env('APP_NAME', 'skeleton'), 'app_env' => env('APP_ENV', 'dev'), 'scan_cacheable' => true, StdoutLoggerInterface::class => ['log_level' => [LogLevel::ALERT, LogLevel::CRITICAL, LogLevel::DEBUG, LogLevel::EMERGENCY, LogLevel::ERROR, LogLevel::INFO, LogLevel::NOTICE, LogLevel::WARNING]]];", $code);
|
||||
}
|
||||
}
|
3
src/phar/tests/fixtures/01-empty/composer.json
vendored
Normal file
3
src/phar/tests/fixtures/01-empty/composer.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"name": "vendor/empty"
|
||||
}
|
3
src/phar/tests/fixtures/02-no-composer/README.md
vendored
Normal file
3
src/phar/tests/fixtures/02-no-composer/README.md
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# Readme
|
||||
|
||||
Not a valid project directory (does not contain a `composer.json` file).
|
2
src/phar/tests/fixtures/03-project-with-phars/composer.json
vendored
Normal file
2
src/phar/tests/fixtures/03-project-with-phars/composer.json
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
2
src/phar/tests/fixtures/03-project-with-phars/composer.phar
vendored
Normal file
2
src/phar/tests/fixtures/03-project-with-phars/composer.phar
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
<?php
|
||||
// empty
|
2
src/phar/tests/fixtures/03-project-with-phars/phar-composer.phar
vendored
Normal file
2
src/phar/tests/fixtures/03-project-with-phars/phar-composer.phar
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
<?php
|
||||
// empty
|
0
src/phar/tests/fixtures/03-project-with-phars/vendors/.gitignore
vendored
Normal file
0
src/phar/tests/fixtures/03-project-with-phars/vendors/.gitignore
vendored
Normal file
2
src/phar/tests/fixtures/04-project-with-phars-in-src/composer.json
vendored
Normal file
2
src/phar/tests/fixtures/04-project-with-phars-in-src/composer.json
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
2
src/phar/tests/fixtures/04-project-with-phars-in-src/src/composer.phar
vendored
Normal file
2
src/phar/tests/fixtures/04-project-with-phars-in-src/src/composer.phar
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
<?php
|
||||
// empty
|
2
src/phar/tests/fixtures/04-project-with-phars-in-src/src/phar-composer.phar
vendored
Normal file
2
src/phar/tests/fixtures/04-project-with-phars-in-src/src/phar-composer.phar
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
<?php
|
||||
// empty
|
0
src/phar/tests/fixtures/04-project-with-phars-in-src/vendors/.gitignore
vendored
Normal file
0
src/phar/tests/fixtures/04-project-with-phars-in-src/vendors/.gitignore
vendored
Normal file
3
src/phar/tests/fixtures/05-invalid-bin/composer.json
vendored
Normal file
3
src/phar/tests/fixtures/05-invalid-bin/composer.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"bin": ["bin/invalid"]
|
||||
}
|
5
src/phar/tests/fixtures/06-dependency-without-dir/composer.json
vendored
Normal file
5
src/phar/tests/fixtures/06-dependency-without-dir/composer.json
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"require": {
|
||||
"roave/security-advisories": "dev-master"
|
||||
}
|
||||
}
|
@ -21,9 +21,9 @@ return [
|
||||
'engine' => [
|
||||
'elasticsearch' => [
|
||||
'driver' => Hyperf\Scout\Provider\ElasticsearchProvider::class,
|
||||
'index' => env('ELASTICSEARCH_INDEX', 'hyperf'),
|
||||
'index' => null,
|
||||
'hosts' => [
|
||||
env('ELASTICSEARCH_HOST', 'http://localhost'),
|
||||
env('ELASTICSEARCH_HOST', 'http://127.0.0.1:9200'),
|
||||
],
|
||||
],
|
||||
],
|
||||
|
@ -209,18 +209,24 @@ class Server implements ServerInterface
|
||||
|
||||
protected function defaultCallbacks()
|
||||
{
|
||||
$hasCallback = class_exists(Bootstrap\StartCallback::class) &&
|
||||
class_exists(Bootstrap\ManagerStartCallback::class) &&
|
||||
class_exists(Bootstrap\WorkerStartCallback::class);
|
||||
$hasCallback = class_exists(Bootstrap\StartCallback::class)
|
||||
&& class_exists(Bootstrap\ManagerStartCallback::class)
|
||||
&& class_exists(Bootstrap\WorkerStartCallback::class);
|
||||
|
||||
if ($hasCallback) {
|
||||
return [
|
||||
Event::ON_START => [Bootstrap\StartCallback::class, 'onStart'],
|
||||
$callbacks = [
|
||||
Event::ON_MANAGER_START => [Bootstrap\ManagerStartCallback::class, 'onManagerStart'],
|
||||
Event::ON_WORKER_START => [Bootstrap\WorkerStartCallback::class, 'onWorkerStart'],
|
||||
Event::ON_WORKER_STOP => [Bootstrap\WorkerStopCallback::class, 'onWorkerStop'],
|
||||
Event::ON_WORKER_EXIT => [Bootstrap\WorkerExitCallback::class, 'onWorkerExit'],
|
||||
];
|
||||
if ($this->server->mode === SWOOLE_BASE) {
|
||||
return $callbacks;
|
||||
}
|
||||
|
||||
return array_merge([
|
||||
Event::ON_START => [Bootstrap\StartCallback::class, 'onStart'],
|
||||
], $callbacks);
|
||||
}
|
||||
|
||||
return [
|
||||
|
@ -74,6 +74,11 @@ class Parallel
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function count(): int
|
||||
{
|
||||
return count($this->callbacks);
|
||||
}
|
||||
|
||||
public function clear(): void
|
||||
{
|
||||
$this->callbacks = [];
|
||||
|
@ -216,6 +216,25 @@ class ParallelTest extends TestCase
|
||||
}
|
||||
}
|
||||
|
||||
public function testParallelCount()
|
||||
{
|
||||
$parallel = new Parallel();
|
||||
$id = 0;
|
||||
$parallel->add(static function () use (&$id) {
|
||||
++$id;
|
||||
});
|
||||
$parallel->add(static function () use (&$id) {
|
||||
++$id;
|
||||
});
|
||||
$this->assertSame(2, $parallel->count());
|
||||
$parallel->wait();
|
||||
$this->assertSame(2, $parallel->count());
|
||||
$this->assertSame(2, $id);
|
||||
$parallel->wait();
|
||||
$this->assertSame(2, $parallel->count());
|
||||
$this->assertSame(4, $id);
|
||||
}
|
||||
|
||||
public function returnCoId()
|
||||
{
|
||||
return Coroutine::id();
|
||||
|
@ -146,7 +146,7 @@ trait ValidatesAttributes
|
||||
return false;
|
||||
}
|
||||
|
||||
return preg_match('/^[\pL\pM\pN_-]+$/u', $value) > 0;
|
||||
return preg_match('/^[\pL\pM\pN_-]+$/u', (string) $value) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -20,6 +20,34 @@ use PHPUnit\Framework\TestCase;
|
||||
*/
|
||||
class ValidateAttributesTest extends TestCase
|
||||
{
|
||||
public function testValidateAlpha()
|
||||
{
|
||||
$validator = new ValidatesAttributesStub();
|
||||
$this->assertTrue($validator->validateAlpha('', 'xxx'));
|
||||
$this->assertTrue($validator->validateAlpha('', '你好'));
|
||||
|
||||
$this->assertFalse($validator->validateAlpha('', '123'));
|
||||
$this->assertFalse($validator->validateAlpha('', '123f1'));
|
||||
$this->assertFalse($validator->validateAlpha('', 123));
|
||||
$this->assertFalse($validator->validateAlpha('', 123.1));
|
||||
$this->assertFalse($validator->validateAlpha('', '123_f1'));
|
||||
$this->assertFalse($validator->validateAlpha('', 'xxx_yy'));
|
||||
}
|
||||
|
||||
public function testValidateAlphaDash()
|
||||
{
|
||||
$validator = new ValidatesAttributesStub();
|
||||
$this->assertTrue($validator->validateAlphaDash('', 'xxx'));
|
||||
$this->assertTrue($validator->validateAlphaDash('', 'xxx_yy'));
|
||||
$this->assertTrue($validator->validateAlphaDash('', '你好'));
|
||||
$this->assertTrue($validator->validateAlphaDash('', '123'));
|
||||
$this->assertTrue($validator->validateAlphaDash('', '123f1'));
|
||||
$this->assertTrue($validator->validateAlphaDash('', 123));
|
||||
$this->assertTrue($validator->validateAlphaDash('', '123_f1'));
|
||||
|
||||
$this->assertFalse($validator->validateAlphaDash('', 123.1));
|
||||
}
|
||||
|
||||
public function testValidateAlphaNum()
|
||||
{
|
||||
$validator = new ValidatesAttributesStub();
|
||||
@ -27,8 +55,10 @@ class ValidateAttributesTest extends TestCase
|
||||
$this->assertTrue($validator->validateAlphaNum('', '123'));
|
||||
$this->assertTrue($validator->validateAlphaNum('', '123f1'));
|
||||
$this->assertTrue($validator->validateAlphaNum('', 123));
|
||||
$this->assertTrue($validator->validateAlphaNum('', '你好'));
|
||||
|
||||
$this->assertFalse($validator->validateAlphaNum('', 123.1));
|
||||
$this->assertFalse($validator->validateAlphaNum('', '123_f1'));
|
||||
$this->assertFalse($validator->validateAlphaNum('', 'xxx_yy'));
|
||||
}
|
||||
}
|
||||
|
@ -9,15 +9,14 @@ declare(strict_types=1);
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
use Hyperf\View\Engine\NoneEngine;
|
||||
use Hyperf\View\Mode;
|
||||
use Hyperf\ViewEngine\HyperfViewEngine;
|
||||
|
||||
return [
|
||||
'engine' => HyperfViewEngine::class,
|
||||
'engine' => NoneEngine::class,
|
||||
'mode' => Mode::SYNC,
|
||||
'config' => [
|
||||
'view_path' => BASE_PATH . '/storage/view/',
|
||||
'cache_path' => BASE_PATH . '/runtime/view/',
|
||||
'charset' => 'UTF-8',
|
||||
],
|
||||
];
|
||||
|
57
src/view/src/Engine/NoneEngine.php
Normal file
57
src/view/src/Engine/NoneEngine.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\View\Engine;
|
||||
|
||||
class NoneEngine implements EngineInterface
|
||||
{
|
||||
public function render($template, $data, $config): string
|
||||
{
|
||||
return <<<'HTML'
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<title>Hyperf</title>
|
||||
|
||||
<!-- Fonts -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css"
|
||||
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="jumbotron">
|
||||
<h1>Hyperf</h1>
|
||||
<p>Hyperf is an extremely performant and flexible PHP CLI framework based on Swoole 4.5+, powered by the
|
||||
state-of-the-art coroutine server and a large number of battle-tested components. Aside from the decisive
|
||||
benchmark outmatching against PHP-FPM frameworks, Hyperf also distinct itself by its focus on flexibility
|
||||
and composability. Hyperf ships with an AOP-enabling dependency injector to ensure components and classes
|
||||
are pluggable and meta programmable. All of its core components strictly follow the PSR standards and thus
|
||||
can be used in other frameworks.</p>
|
||||
<p><a class="btn btn-primary btn-lg" href="https://hyperf.wiki/" role="button">Learn more</a></p>
|
||||
<p>This view engine is not available, please use engines below.</p>
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item"><a href="https://github.com/hyperf/view-engine">hyperf/view-engine</a></li>
|
||||
<li class="list-group-item"><a href="https://github.com/duncan3dc/blade">duncan3dc/blade</a></li>
|
||||
<li class="list-group-item"><a href="https://github.com/smarty-php/smarty">smarty/smarty</a></li>
|
||||
<li class="list-group-item"><a href="https://github.com/twigphp/Twig">twig/twig</a></li>
|
||||
<li class="list-group-item"><a href="https://github.com/thephpleague/plates">league/plates</a></li>
|
||||
<li class="list-group-item"><a href="https://github.com/sy-records/think-template">sy-records/think-template</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
HTML;
|
||||
}
|
||||
}
|
@ -17,7 +17,7 @@ use Hyperf\Task\Task;
|
||||
use Hyperf\Task\TaskExecutor;
|
||||
use Hyperf\Utils\Context;
|
||||
use Hyperf\View\Engine\EngineInterface;
|
||||
use Hyperf\View\Engine\SmartyEngine;
|
||||
use Hyperf\View\Engine\NoneEngine;
|
||||
use Hyperf\View\Exception\EngineNotFindException;
|
||||
use Hyperf\View\Exception\RenderException;
|
||||
use Psr\Container\ContainerInterface;
|
||||
@ -47,7 +47,7 @@ class Render implements RenderInterface
|
||||
|
||||
public function __construct(ContainerInterface $container, ConfigInterface $config)
|
||||
{
|
||||
$engine = $config->get('view.engine', SmartyEngine::class);
|
||||
$engine = $config->get('view.engine', NoneEngine::class);
|
||||
if (! $container->has($engine)) {
|
||||
throw new EngineNotFindException("{$engine} engine is not found.");
|
||||
}
|
||||
|
29
src/view/tests/NoneTest.php
Normal file
29
src/view/tests/NoneTest.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace HyperfTest\View;
|
||||
|
||||
use Hyperf\View\Engine\NoneEngine;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @coversNothing
|
||||
*/
|
||||
class NoneTest extends TestCase
|
||||
{
|
||||
public function testRender()
|
||||
{
|
||||
$content = (new NoneEngine())->render('/', [], []);
|
||||
|
||||
$this->assertNotEmpty($content);
|
||||
}
|
||||
}
|
@ -16,6 +16,7 @@ use Hyperf\Di\Annotation\AnnotationReader;
|
||||
use Hyperf\Di\ClassLoader;
|
||||
use Hyperf\Utils\Codec\Json;
|
||||
use Hyperf\Utils\Coroutine;
|
||||
use Hyperf\Utils\Exception\InvalidArgumentException;
|
||||
use Hyperf\Utils\Filesystem\FileNotFoundException;
|
||||
use Hyperf\Utils\Filesystem\Filesystem;
|
||||
use Hyperf\Watcher\Driver\DriverInterface;
|
||||
@ -157,6 +158,10 @@ class Watcher
|
||||
if (empty($file)) {
|
||||
throw new FileNotFoundException('The config of pid_file is not found.');
|
||||
}
|
||||
$daemonize = $this->config->get('server.settings.daemonize', false);
|
||||
if ($daemonize) {
|
||||
throw new InvalidArgumentException('Please set `server.settings.daemonize` to false');
|
||||
}
|
||||
if (! $isStart && $this->filesystem->exists($file)) {
|
||||
$pid = $this->filesystem->get($file);
|
||||
try {
|
||||
|
@ -231,7 +231,11 @@ class Server implements MiddlewareInitializerInterface, OnHandShakeInterface, On
|
||||
return;
|
||||
}
|
||||
|
||||
$instance->onMessage($server, $frame);
|
||||
try {
|
||||
$instance->onMessage($server, $frame);
|
||||
} catch (\Throwable $exception) {
|
||||
$this->logger->error((string) $exception);
|
||||
}
|
||||
}
|
||||
|
||||
public function onClose($server, int $fd, int $reactorId): void
|
||||
@ -252,7 +256,11 @@ class Server implements MiddlewareInitializerInterface, OnHandShakeInterface, On
|
||||
|
||||
$instance = $this->container->get($fdObj->class);
|
||||
if ($instance instanceof OnCloseInterface) {
|
||||
$instance->onClose($server, $fd, $reactorId);
|
||||
try {
|
||||
$instance->onClose($server, $fd, $reactorId);
|
||||
} catch (\Throwable $exception) {
|
||||
$this->logger->error((string) $exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user