mirror of
https://gitee.com/hyperf/hyperf.git
synced 2024-12-02 03:37:44 +08:00
Merge remote-tracking branch 'upstream/master' into pr/1969
This commit is contained in:
commit
380cf96c3e
12
.travis.yml
12
.travis.yml
@ -5,11 +5,11 @@ sudo: required
|
||||
matrix:
|
||||
include:
|
||||
- php: 7.2
|
||||
env: SW_VERSION="4.5.2"
|
||||
env: SW_VERSION="4.5.3"
|
||||
- php: 7.3
|
||||
env: SW_VERSION="4.5.2"
|
||||
env: SW_VERSION="4.5.3"
|
||||
- php: 7.4
|
||||
env: SW_VERSION="4.5.2"
|
||||
env: SW_VERSION="4.5.3"
|
||||
|
||||
services:
|
||||
- mysql
|
||||
@ -29,6 +29,7 @@ install:
|
||||
- phpenv config-add .travis/ci.ini
|
||||
- bash .travis/setup.mysql.sh
|
||||
- docker run -d --name dev-consul -e CONSUL_BIND_INTERFACE=eth0 -p 8500:8500 consul
|
||||
- docker run --name nsq -p 4150:4150 -p 4151:4151 -p 4160:4160 -p 4161:4161 -p 4170:4170 -p 4171:4171 --entrypoint /bin/nsqd -d nsqio/nsq:latest
|
||||
|
||||
before_script:
|
||||
- cd $TRAVIS_BUILD_DIR
|
||||
@ -37,4 +38,7 @@ before_script:
|
||||
script:
|
||||
- composer analyse src
|
||||
- composer test -- --exclude-group NonCoroutine
|
||||
- vendor/bin/phpunit --group NonCoroutine
|
||||
- vendor/bin/phpunit --group NonCoroutine
|
||||
|
||||
notifications:
|
||||
webhooks: https://oapi.dingtalk.com/robot/send?access_token=72c12e591c435f0f41e09261f6252aeafd284e432657b1f8d4a77b5aac8fbfcd
|
||||
|
@ -1,4 +1,84 @@
|
||||
# v2.0.6 - TBD
|
||||
# v2.0.10 - TBD
|
||||
|
||||
## Added
|
||||
|
||||
- [#2411](https://github.com/hyperf/hyperf/pull/2411) Added method `Hyperf\Database\Query\Builder::forPageBeforeId` for database.
|
||||
- [#2420](https://github.com/hyperf/hyperf/pull/2420) [#2426](https://github.com/hyperf/hyperf/pull/2426) Added option `enable-event-dispatcher` to initialize EventDispatcher for command.
|
||||
- [#2441](https://github.com/hyperf/hyperf/pull/2441) Added some setters for `SocketIO`.
|
||||
|
||||
## Fixed
|
||||
|
||||
- [#2427](https://github.com/hyperf/hyperf/pull/2427) Fixed model event dispatcher does not works for `Pivot` and `MorphPivot`.
|
||||
- [#2443](https://github.com/hyperf/hyperf/pull/2443) Fixed traceid does not exists when using coroutine handler.
|
||||
|
||||
## Optimized
|
||||
|
||||
- [#2429](https://github.com/hyperf/hyperf/pull/2429) Optimized error message when does not set the value of `@var` for `@Inject`.
|
||||
- [#2438](https://github.com/hyperf/hyperf/pull/2438) Optimized code for deleting model cache when model deleted or saved in transaction.
|
||||
|
||||
# v2.0.9 - 2020-08-31
|
||||
|
||||
## Added
|
||||
|
||||
- [#2331](https://github.com/hyperf/hyperf/pull/2331) Added auth api for [hyperf/nacos](https://github.com/hyperf/nacos) component.
|
||||
- [#2331](https://github.com/hyperf/hyperf/pull/2331) Added config `nacos.enable` to control the [hyperf/nacos](https://github.com/hyperf/nacos) component.
|
||||
- [#2331](https://github.com/hyperf/hyperf/pull/2331) Added array merge mode for [hyperf/nacos](https://github.com/hyperf/nacos) component.
|
||||
- [#2377](https://github.com/hyperf/hyperf/pull/2377) Added `ts` header for gRPC request of client, compatible with Node.js gRPC server etc.
|
||||
- [#2384](https://github.com/hyperf/hyperf/pull/2384) Added global function `optional()` to create `Hyperf\Utils\Optional` object or for more convenient way to use.
|
||||
|
||||
## Fixed
|
||||
|
||||
- [#2331](https://github.com/hyperf/hyperf/pull/2331) Fixed exception thrown when the service or config was not found for [hyperf/nacos](https://github.com/hyperf/nacos) component.
|
||||
- [#2356](https://github.com/hyperf/hyperf/pull/2356) [#2368](https://github.com/hyperf/hyperf/pull/2368) Fixed `server:start` failed, when the config of pid_file changed.
|
||||
- [#2358](https://github.com/hyperf/hyperf/pull/2358) Fixed validation rule `digits` does not support `int`.
|
||||
|
||||
## Optimized
|
||||
|
||||
- [#2359](https://github.com/hyperf/hyperf/pull/2359) Optimized custom process which stop friendly when running in coroutine server.
|
||||
- [#2363](https://github.com/hyperf/hyperf/pull/2363) Optimized [hyperf/di](https://github.com/hyperf/di) component which is no need to depend on [hyperf/config](https://github.com/hyperf/config) component.
|
||||
- [#2373](https://github.com/hyperf/hyperf/pull/2373) Optimized the exception handler which add `content-type` header automatically by default for [hyperf/validation](https://github.com/hyperf/validation) component.
|
||||
|
||||
# v2.0.8 - 2020-08-24
|
||||
|
||||
## Added
|
||||
|
||||
- [#2334](https://github.com/hyperf/hyperf/pull/2334) Added method `Arr::merge` to merge array more friendly than `array_merge_recursive`.
|
||||
- [#2335](https://github.com/hyperf/hyperf/pull/2335) Added `Hyperf/Utils/Optional` which accepts any argument and allows you to access properties or call methods on that object.
|
||||
- [#2336](https://github.com/hyperf/hyperf/pull/2336) Added `RedisNsqAdapter` which publish message through nsq for `socketio-server`.
|
||||
|
||||
## Fixed
|
||||
|
||||
- [#2338](https://github.com/hyperf/hyperf/pull/2338) Fixed filesystem does not works when using s3 adapter.
|
||||
- [#2340](https://github.com/hyperf/hyperf/pull/2340) Fixed `__FUNCTION__` and `__METHOD__` magic constants does work in closure of aop proxy class
|
||||
|
||||
## Optimized
|
||||
|
||||
- [#2319](https://github.com/hyperf/hyperf/pull/2319) Optimized the `ResolverDispatcher` which is friendly for circular dependencies.
|
||||
|
||||
## Dependencies Upgrade
|
||||
|
||||
- Upgraded `markrogoyski/math-php` requirement from `^0.49.0` to `^1.2.0`
|
||||
|
||||
# v2.0.7 - 2020-08-17
|
||||
|
||||
## Added
|
||||
|
||||
- [#2307](https://github.com/hyperf/hyperf/pull/2307) [#2312](https://github.com/hyperf/hyperf/pull/2312) Added NSQD HTTP API client support for [hyperf/nsq](https://github.com/hyperf/nsq) component.
|
||||
|
||||
## Fixed
|
||||
|
||||
- [#2275](https://github.com/hyperf/hyperf/pull/2275) Fixed bug that fetch process blocking for config center.
|
||||
- [#2276](https://github.com/hyperf/hyperf/pull/2276) Fixed bug that the config is cleared when the config is not modified in apollo.
|
||||
- [#2280](https://github.com/hyperf/hyperf/pull/2280) Fixed bug that interface methods will be rewriten by aop.
|
||||
- [#2281](https://github.com/hyperf/hyperf/pull/2281) Fixed `co::create` failed in non-coroutine environment for `hyperf/signal`.
|
||||
- [#2304](https://github.com/hyperf/hyperf/pull/2304) Fixed dead cycle when del sid for socketio memory adapter.
|
||||
- [#2309](https://github.com/hyperf/hyperf/pull/2309) Fixed JsonRpcHttpTransporter cannot set the custom timeout property.
|
||||
|
||||
# v2.0.6 - 2020-08-10
|
||||
|
||||
## Added
|
||||
|
||||
- [#2125](https://github.com/hyperf/hyperf/pull/2125) Added Jet component, Jet is a unification model RPC Client, built-in JSONRPC protocol, available to running in ALL PHP environments, including PHP-FPM and Swoole/Hyperf environments.
|
||||
|
||||
## Fixed
|
||||
|
||||
|
18
README-CN.md
18
README-CN.md
@ -63,22 +63,6 @@ Hyperf 还提供了 `基于 PSR-11 的依赖注入容器`、`注解`、`AOP 面
|
||||
|
||||
以组织/公司的名义赞助 Hyperf 项目的发展,您的 LOGO 和链接可以呈现在下方。 [[赞助](https://hyperf.wiki/#/zh/donate)]
|
||||
|
||||
## 金牌赞助方
|
||||
|
||||
<!--gold start-->
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left" valign="middle">
|
||||
<a href="https://guojiang.club/?utm_source=hyperf&utm_campaign=sponsor" target="_blank">
|
||||
<img height="110px" src="https://hyperf.wiki/zh-cn/imgs/guojiang-club.jpg">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<!--gold end-->
|
||||
|
||||
# 性能
|
||||
|
||||
### 阿里云 8 核 16G
|
||||
@ -98,6 +82,8 @@ Transfer/sec: 18.83MB
|
||||
# Hyperf 生态
|
||||
|
||||
- 🧬 [Nano](https://github.com/hyperf/nano) 是一款零配置、无骨架、极小化的 Hyperf 发行版,通过 Nano 可以让您仅仅通过 1 个 PHP 文件即可快速搭建一个 Hyperf 应用。
|
||||
- ⚡️ [GoTask](https://github.com/hyperf/gotask) 是一款可以启动 Go 进程作为 Swoole 主进程边车(Sidecar) 的一个库,利用 IPC 进程通讯将任务投递给边车处理并接收返回值,可以理解为 Go 语言版的 Swoole TaskWorker。
|
||||
- 🚀 [Jet](https://github.com/hyperf/jet) 是一个统一模型的 RPC 客户端,内置 JSONRPC 协议的适配,该组件可适用于所有的 PHP 环境,包括 PHP-FPM 和 Swoole 或 Hyperf。
|
||||
|
||||
# 开源协议
|
||||
|
||||
|
18
README.md
18
README.md
@ -51,22 +51,6 @@ Become a financial contributor and help us sustain our community. [[Contribute](
|
||||
|
||||
Support this project with your organization or company. Your logo will show up here with a link to your website. [[Contribute](https://hyperf.wiki/#/en/donate)]
|
||||
|
||||
## Gold Sponsors
|
||||
|
||||
<!--gold start-->
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left" valign="middle">
|
||||
<a href="https://guojiang.club/?utm_source=hyperf&utm_campaign=sponsor" target="_blank">
|
||||
<img height="110px" src="https://hyperf.wiki/zh-cn/imgs/guojiang-club.jpg">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<!--gold end-->
|
||||
|
||||
# Performance
|
||||
|
||||
### Aliyun 8 cores 16G ram
|
||||
@ -86,6 +70,8 @@ Transfer/sec: 18.83MB
|
||||
# The Hyperf Ecosystem
|
||||
|
||||
- 🧬 [Nano](https://github.com/hyperf/nano) is a zero-config, no skeleton, minimal Hyperf distribution that allows you to quickly build a Hyperf application with just a single PHP file.
|
||||
- ⚡️ [GoTask](https://github.com/hyperf/gotask) is a library to spawns a go process as a Swoole sidecar and establishes a bi-directional IPC to offload heavy-duties to Go. Think of it as a Swoole Taskworker in Go.
|
||||
- 🚀 [Jet](https://github.com/hyperf/jet) is a unification model RPC Client, built-in JSONRPC protocol, available to running in ALL PHP environments, including PHP-FPM and Swoole/Hyperf environments.
|
||||
|
||||
# License
|
||||
|
||||
|
@ -48,14 +48,14 @@
|
||||
"ircmaxell/random-lib": "^1.2",
|
||||
"jcchavezs/zipkin-opentracing": "^0.1.5",
|
||||
"jean85/pretty-package-versions": "^1.2",
|
||||
"jonahgeorge/jaeger-client-php": "^0.4.4",
|
||||
"jonahgeorge/jaeger-client-php": "^0.6.0",
|
||||
"laminas/laminas-mime": "^2.7",
|
||||
"league/flysystem": "^1.0",
|
||||
"league/flysystem-aws-s3-v3": "^1.0",
|
||||
"league/flysystem-memory": "^1.0",
|
||||
"league/plates": "^3.3",
|
||||
"malukenho/docheader": "^0.1.6",
|
||||
"markrogoyski/math-php": "^0.49.0",
|
||||
"markrogoyski/math-php": "^1.2.0",
|
||||
"mix/redis-subscribe": "^2.1",
|
||||
"mockery/mockery": "^1.0",
|
||||
"monolog/monolog": "^2.0",
|
||||
|
@ -1,5 +1,93 @@
|
||||
# Changelogs
|
||||
|
||||
# v2.0.9 - 2020-08-31
|
||||
|
||||
## Added
|
||||
|
||||
- [#2331](https://github.com/hyperf/hyperf/pull/2331) Added auth api for [hyperf/nacos](https://github.com/hyperf/nacos) component.
|
||||
- [#2331](https://github.com/hyperf/hyperf/pull/2331) Added config `nacos.enable` to control the [hyperf/nacos](https://github.com/hyperf/nacos) component.
|
||||
- [#2331](https://github.com/hyperf/hyperf/pull/2331) Added array merge mode for [hyperf/nacos](https://github.com/hyperf/nacos) component.
|
||||
- [#2377](https://github.com/hyperf/hyperf/pull/2377) Added `ts` header for gRPC request of client, compatible with Node.js gRPC server etc.
|
||||
- [#2384](https://github.com/hyperf/hyperf/pull/2384) Added global function `optional()` to create `Hyperf\Utils\Optional` object or for more convenient way to use.
|
||||
|
||||
## Fixed
|
||||
|
||||
- [#2331](https://github.com/hyperf/hyperf/pull/2331) Fixed exception thrown when the service or config was not found for [hyperf/nacos](https://github.com/hyperf/nacos) component.
|
||||
- [#2356](https://github.com/hyperf/hyperf/pull/2356) [#2368](https://github.com/hyperf/hyperf/pull/2368) Fixed `server:start` failed, when the config of pid_file changed.
|
||||
- [#2358](https://github.com/hyperf/hyperf/pull/2358) Fixed validation rule `digits` does not support `int`.
|
||||
|
||||
## Optimized
|
||||
|
||||
- [#2359](https://github.com/hyperf/hyperf/pull/2359) Optimized custom process which stop friendly when running in coroutine server.
|
||||
- [#2363](https://github.com/hyperf/hyperf/pull/2363) Optimized [hyperf/di](https://github.com/hyperf/di) component which is no need to depend on [hyperf/config](https://github.com/hyperf/config) component.
|
||||
- [#2373](https://github.com/hyperf/hyperf/pull/2373) Optimized the exception handler which add `content-type` header automatically by default for [hyperf/validation](https://github.com/hyperf/validation) component.
|
||||
|
||||
# v2.0.8 - 2020-08-24
|
||||
|
||||
## Added
|
||||
|
||||
- [#2334](https://github.com/hyperf/hyperf/pull/2334) Added method `Arr::merge` to merge array more friendly than `array_merge_recursive`.
|
||||
- [#2335](https://github.com/hyperf/hyperf/pull/2335) Added `Hyperf/Utils/Optional` which accepts any argument and allows you to access properties or call methods on that object.
|
||||
- [#2336](https://github.com/hyperf/hyperf/pull/2336) Added `RedisNsqAdapter` which publish message through nsq for `socketio-server`.
|
||||
|
||||
## Fixed
|
||||
|
||||
- [#2338](https://github.com/hyperf/hyperf/pull/2338) Fixed filesystem does not works when using s3 adapter.
|
||||
- [#2340](https://github.com/hyperf/hyperf/pull/2340) Fixed `__FUNCTION__` and `__METHOD__` magic constants does work in closure of aop proxy class
|
||||
|
||||
## Optimized
|
||||
|
||||
- [#2319](https://github.com/hyperf/hyperf/pull/2319) Optimized the `ResolverDispatcher` which is friendly for circular dependencies.
|
||||
|
||||
## Dependencies Upgrade
|
||||
|
||||
- Upgraded `markrogoyski/math-php` requirement from `^0.49.0` to `^1.2.0`
|
||||
|
||||
# v2.0.7 - 2020-08-17
|
||||
|
||||
## Added
|
||||
|
||||
- [#2307](https://github.com/hyperf/hyperf/pull/2307) [#2312](https://github.com/hyperf/hyperf/pull/2312) Added NSQD HTTP API client support for [hyperf/nsq](https://github.com/hyperf/nsq) component.
|
||||
|
||||
## Fixed
|
||||
|
||||
- [#2275](https://github.com/hyperf/hyperf/pull/2275) Fixed bug that fetch process blocking for config center.
|
||||
- [#2276](https://github.com/hyperf/hyperf/pull/2276) Fixed bug that the config is cleared when the config is not modified in apollo.
|
||||
- [#2280](https://github.com/hyperf/hyperf/pull/2280) Fixed bug that interface methods will be rewriten by aop.
|
||||
- [#2281](https://github.com/hyperf/hyperf/pull/2281) Fixed `co::create` failed in non-coroutine environment for `hyperf/signal`.
|
||||
- [#2304](https://github.com/hyperf/hyperf/pull/2304) Fixed dead cycle when del sid for socketio memory adapter.
|
||||
- [#2309](https://github.com/hyperf/hyperf/pull/2309) Fixed JsonRpcHttpTransporter cannot set the custom timeout property.
|
||||
|
||||
# v2.0.6 - 2020-08-10
|
||||
|
||||
## Added
|
||||
|
||||
- [#2125](https://github.com/hyperf/hyperf/pull/2125) Added Jet component, Jet is a unification model RPC Client, built-in JSONRPC protocol, available to running in ALL PHP environments, including PHP-FPM and Swoole/Hyperf environments.
|
||||
|
||||
## Fixed
|
||||
|
||||
- [#2236](https://github.com/hyperf/hyperf/pull/2236) Fixed bug that select node failed when using `loadBalancer` for nacos.
|
||||
- [#2242](https://github.com/hyperf/hyperf/pull/2242) Fixed bug that collect more than once time when using watcher.
|
||||
|
||||
# v2.0.5 - 2020-08-03
|
||||
|
||||
## Added
|
||||
|
||||
- [#2001](https://github.com/hyperf/hyperf/pull/2001) Added `$signature` to init command easily.
|
||||
- [#2204](https://github.com/hyperf/hyperf/pull/2204) Added `$concurrent` for function `parallel`.
|
||||
|
||||
## Fixed
|
||||
|
||||
- [#2210](https://github.com/hyperf/hyperf/pull/2210) Fixed bug that open event won't be executed after handshake right now.
|
||||
- [#2214](https://github.com/hyperf/hyperf/pull/2214) Fixed bug that close event won't be executed when close the connection by websocket server.
|
||||
- [#2218](https://github.com/hyperf/hyperf/pull/2218) Fixed bug that sender does not works for coroutine server.
|
||||
- [#2227](https://github.com/hyperf/hyperf/pull/2227) Fixed context won't be destroyed when accept keepalive connection for co server.
|
||||
|
||||
## Optimized
|
||||
|
||||
- [#2193](https://github.com/hyperf/hyperf/pull/2193) Optimized the scan accuracy for `Hyperf\Watcher\Driver\FindDriver`.
|
||||
- [#2232](https://github.com/hyperf/hyperf/pull/2232) Optimized eager load when the type is `In` or `InRaw` for model-cache.
|
||||
|
||||
# v2.0.4 - 2020-07-27
|
||||
|
||||
## Added
|
||||
@ -221,6 +309,7 @@ return [
|
||||
- [#1896](https://github.com/hyperf/hyperf/pull/1896) Keys will be merged when different constants use the same code.
|
||||
|
||||
|
||||
|
||||
# v1.1.32 - 2020-05-21
|
||||
|
||||
## Fixed
|
||||
|
125
docs/en/jet.md
Normal file
125
docs/en/jet.md
Normal file
@ -0,0 +1,125 @@
|
||||
# Jet, by Hyperf
|
||||
|
||||
Jet is a unification model RPC Client, built-in JSONRPC protocol, available to running in ALL PHP environments, including PHP-FPM and Swoole/Hyperf environments.
|
||||
|
||||
> Also will built-in gRPC and Tars protocols in future.
|
||||
|
||||
# Installation
|
||||
|
||||
```bash
|
||||
composer require hyperf/jet
|
||||
```
|
||||
|
||||
# Quickstart
|
||||
|
||||
## Register protocol
|
||||
|
||||
> Register the protocol is not necessary, but you could manage the protocols more easily by using ProtocolManager.
|
||||
|
||||
You cloud register any protocol by `Hyperf\Jet\ProtocolManager`, per protocol basically including Transporter, Packer, DataFormatter and PathGenerator, you could register a JSONRPC protocol like below:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use Hyperf\Jet\DataFormatter\DataFormatter;
|
||||
use Hyperf\Jet\Packer\JsonEofPacker;
|
||||
use Hyperf\Jet\PathGenerator\PathGenerator;
|
||||
use Hyperf\Jet\ProtocolManager;
|
||||
use Hyperf\Jet\Transporter\StreamSocketTransporter;
|
||||
|
||||
ProtocolManager::register($protocol = 'jsonrpc', [
|
||||
ProtocolManager::TRANSPORTER => new StreamSocketTransporter(),
|
||||
ProtocolManager::PACKER => new JsonEofPacker(),
|
||||
ProtocolManager::PATH_GENERATOR => new PathGenerator(),
|
||||
ProtocolManager::DATA_FORMATTER => new DataFormatter(),
|
||||
]);
|
||||
```
|
||||
|
||||
## Register service
|
||||
|
||||
> Register the service is not necessary, but you could manage the services more easily by using ServiceManager.
|
||||
|
||||
After you registered a protocol to `Hyperf\Jet\ProtocolManager`, you could bind the protocol with any services by `Hyperf\Jet\ServiceManager`, like below:
|
||||
|
||||
```php
|
||||
<?php
|
||||
use Hyperf\Jet\ServiceManager;
|
||||
|
||||
// Bind CalculatorService with jsonrpc protocol, and set the static nodes info.
|
||||
ServiceManager::register($service = 'CalculatorService', $protocol = 'jsonrpc', [
|
||||
ServiceManager::NODES => [
|
||||
[$host = '127.0.0.1', $port = 9503],
|
||||
],
|
||||
]);
|
||||
```
|
||||
|
||||
## Call RPC method
|
||||
|
||||
### Call by ClientFactory
|
||||
|
||||
After you registered the protocol and service, you could get your service client via `Hyperf/Jet/ClientFactory`, like below:
|
||||
|
||||
```php
|
||||
<?php
|
||||
use Hyperf\Jet\ClientFactory;
|
||||
|
||||
$clientFactory = new ClientFactory();
|
||||
$client = $clientFactory->create($service = 'CalculatorService', $protocol = 'jsonrpc');
|
||||
```
|
||||
|
||||
When you have the client object, you could call any remote methods via the object, like below:
|
||||
|
||||
```php
|
||||
// Call the remote method `add` with arguments `1` and `2`.
|
||||
// The $result is the result of the remote method.
|
||||
$result = $client->add(1, 2);
|
||||
```
|
||||
|
||||
If you call a not exist remote method, the client will throw an `Hyperf\Jet\Exception\ServerException` exception.
|
||||
|
||||
### Call by custom client
|
||||
|
||||
You could also create a custom client class which extends `Hyperf\Jet\AbstractClient`, to call the remote methods via the client object.
|
||||
For example, you want to define a RPC client for `CalculatorService` with `jsonrpc` protocol, you could create a `CalculatorService` class firstly, like below:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use Hyperf\Jet\AbstractClient;
|
||||
use Hyperf\Jet\Packer\JsonEofPacker;
|
||||
use Hyperf\Jet\Transporter\StreamSocketTransporter;
|
||||
use Hyperf\Rpc\Contract\DataFormatterInterface;
|
||||
use Hyperf\Rpc\Contract\PackerInterface;
|
||||
use Hyperf\Rpc\Contract\PathGeneratorInterface;
|
||||
use Hyperf\Rpc\Contract\TransporterInterface;
|
||||
|
||||
/**
|
||||
* @method int add(int $a, int $b);
|
||||
*/
|
||||
class CalculatorService extends AbstractClient
|
||||
{
|
||||
// Define `CalculatorService` as the default value of $service.
|
||||
public function __construct(
|
||||
string $service = 'CalculatorService',
|
||||
TransporterInterface $transporter = null,
|
||||
PackerInterface $packer = null,
|
||||
?DataFormatterInterface $dataFormatter = null,
|
||||
?PathGeneratorInterface $pathGenerator = null
|
||||
) {
|
||||
// Specific the transporter here, you could also retrieve the transporter from ProtocolManager or passing by constructor.
|
||||
$transporter = new StreamSocketTransporter('127.0.0.1', 9503);
|
||||
// Specific the packer here, you could also retrieve the packer from ProtocolManager or passing by constructor.
|
||||
$packer = new JsonEofPacker();
|
||||
parent::__construct($service, $transporter, $packer, $dataFormatter, $pathGenerator);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Now, you could use this class to call the remote method directly, like below:
|
||||
|
||||
```php
|
||||
// Call the remote method `add` with arguments `1` and `2`.
|
||||
// The $result is the result of the remote method.
|
||||
$client = new CalculatorService();
|
||||
$result = $client->add(1, 2);
|
||||
```
|
385
docs/en/nsq.md
Normal file
385
docs/en/nsq.md
Normal file
@ -0,0 +1,385 @@
|
||||
# NSQ
|
||||
|
||||
[NSQ](https://nsq.io) is a realtime distributed messaging platform, writting by Golang.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
composer require hyperf/nsq
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Configuration
|
||||
|
||||
The configuration file of the NSQ component is located in `config/autoload/nsq.php` by default. If the file does not exist, you could use the `php bin/hyperf.php vendor:publish hyperf/nsq` command to publish the corresponding configuration file.
|
||||
|
||||
The default configuration file is as follows:
|
||||
|
||||
```php
|
||||
<?php
|
||||
return [
|
||||
'default' => [
|
||||
'host' => '127.0.0.1',
|
||||
'port' => 4150,
|
||||
'pool' => [
|
||||
'min_connections' => 1,
|
||||
'max_connections' => 10,
|
||||
'connect_timeout' => 10.0,
|
||||
'wait_timeout' => 3.0,
|
||||
'heartbeat' => -1,
|
||||
'max_idle_time' => 60.0,
|
||||
],
|
||||
],
|
||||
];
|
||||
```
|
||||
|
||||
### Craete Consumer
|
||||
|
||||
You can quickly generate a consumer to consume the message through the `gen:nsq-consumer` command, for example:
|
||||
|
||||
```bash
|
||||
php bin/hyperf.php gen:nsq-consumer DemoConsumer
|
||||
```
|
||||
|
||||
You could also use the `Hyperf\Nsq\Annotation\Consumer` annotation to declare a subclass of the `Hyperf/Nsq/AbstractConsumer` abstract class to complete the definition of a consumer, where the annotation and the abstract classes both are contain the following properties:
|
||||
|
||||
| Property | Type | Default Value | Comment |
|
||||
|:-------:|:------:|:------:|:----------------:|
|
||||
| topic | string | '' | The topic that you want to listening to |
|
||||
| channel | string | '' | The channel that you want to listening to |
|
||||
| name | string | NsqConsumer | The name of the consumer |
|
||||
| nums | int | 1 | The process numbers of the consumers |
|
||||
| pool | string | default | The connection pool resource corresponding to the consumer, corresponding to the key of the configuration file |
|
||||
|
||||
These annotation properties are optional, because the `Hyperf/Nsq/AbstractConsumer` class also defines the corresponding member properties and getter and setter respectively. When the annotation properties are not defined, the default value of the abstract class will be used.
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Nsq\Consumer;
|
||||
|
||||
use Hyperf\Nsq\AbstractConsumer;
|
||||
use Hyperf\Nsq\Annotation\Consumer;
|
||||
use Hyperf\Nsq\Message;
|
||||
use Hyperf\Nsq\Result;
|
||||
|
||||
/**
|
||||
* @Consumer(
|
||||
* topic="hyperf",
|
||||
* channel="hyperf",
|
||||
* name ="DemoNsqConsumer",
|
||||
* nums=1
|
||||
* )
|
||||
*/
|
||||
class DemoNsqConsumer extends AbstractConsumer
|
||||
{
|
||||
public function consume(Message $payload): string
|
||||
{
|
||||
var_dump($payload->getBody());
|
||||
|
||||
return Result::ACK;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Disable self-starting of the comsumer process
|
||||
|
||||
By default, after using the `@Consumer` annotation definition, the framework will automatically create a child process to start the consumer at startup, and will automatically re-pull it after the child process exits abnormally. However, if some debugging work is carried out in the development stage, it may be inconvenient to debug due to the automatic consumption of consumers.
|
||||
|
||||
In this situation, you could control the self-start of the consumption process through two forms to disable the feature, global shutdown and partial shutdown.
|
||||
|
||||
#### Global shutdown
|
||||
|
||||
You could set the `enable` option of the corresponding connection to `false` in the default configuration file `config/autoload/nsq.php`, which means that all consumer processes under this connection will disable the self-start feature.
|
||||
|
||||
#### Partial shutdown
|
||||
|
||||
When you only need to disable the self-start feature of individual consumer processes, you only need to override the parent method `isEnable()` in the corresponding consumer class and return `false` to disable the consumer's self-start feature.
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Nsq\Consumer;
|
||||
|
||||
use Hyperf\Nsq\AbstractConsumer;
|
||||
use Hyperf\Nsq\Annotation\Consumer;
|
||||
use Hyperf\Nsq\Message;
|
||||
use Hyperf\Nsq\Result;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
/**
|
||||
* @Consumer(
|
||||
* topic="demo_topic",
|
||||
* channel="demo_channel",
|
||||
* name ="DemoConsumer",
|
||||
* nums=1
|
||||
* )
|
||||
*/
|
||||
class DemoConsumer extends AbstractConsumer
|
||||
{
|
||||
public function __construct(ContainerInterface $container)
|
||||
{
|
||||
parent::__construct($container);
|
||||
}
|
||||
|
||||
public function isEnable(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function consume(Message $payload): string
|
||||
{
|
||||
$body = json_decode($payload->getBody(), true);
|
||||
var_dump($body);
|
||||
return Result::ACK;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Publish message
|
||||
|
||||
You could publish a message to NSQ by calling the `Hyperf\Nsq\Nsq::publish(string $topic, $message, float $deferTime = 0.0)` method. The following is an example of publish message in Command:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use Hyperf\Command\Command as HyperfCommand;
|
||||
use Hyperf\Command\Annotation\Command;
|
||||
use Hyperf\Nsq\Nsq;
|
||||
|
||||
/**
|
||||
* @Command
|
||||
*/
|
||||
class NsqCommand extends HyperfCommand
|
||||
{
|
||||
protected $name = 'nsq:pub';
|
||||
|
||||
public function handle()
|
||||
{
|
||||
/** @var Nsq $nsq */
|
||||
$nsq = make(Nsq::class);
|
||||
$topic = 'hyperf';
|
||||
$message = 'This is message at ' . time();
|
||||
$nsq->publish($topic, $message);
|
||||
|
||||
$this->line('success', 'info');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Publish multiple messages at once
|
||||
|
||||
The second parameter of the `Hyperf\Nsq\Nsq::publish(string $topic, $message, float $deferTime = 0.0)` method can not just only pass a string value, but also an array of strings to achieve one-time publish multiple messages to a topic, an example is as follows:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use Hyperf\Command\Command as HyperfCommand;
|
||||
use Hyperf\Command\Annotation\Command;
|
||||
use Hyperf\Nsq\Nsq;
|
||||
|
||||
/**
|
||||
* @Command
|
||||
*/
|
||||
class NsqCommand extends HyperfCommand
|
||||
{
|
||||
protected $name = 'nsq:pub';
|
||||
|
||||
public function handle()
|
||||
{
|
||||
/** @var Nsq $nsq */
|
||||
$nsq = make(Nsq::class);
|
||||
$topic = 'hyperf';
|
||||
$messages = [
|
||||
'This is message 1 at ' . time(),
|
||||
'This is message 2 at ' . time(),
|
||||
'This is message 3 at ' . time(),
|
||||
];
|
||||
$nsq->publish($topic, $messages);
|
||||
|
||||
$this->line('success', 'info');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Publish delay message
|
||||
|
||||
When you want the message you publish to be consumed after a specific time, you could also pass the third parameter of the `Hyperf\Nsq\Nsq::publish(string $topic, $message, float $deferTime = 0.0)` method the delay time corresponding to the publish message, in seconds, an example is as follows:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use Hyperf\Command\Command as HyperfCommand;
|
||||
use Hyperf\Command\Annotation\Command;
|
||||
use Hyperf\Nsq\Nsq;
|
||||
|
||||
/**
|
||||
* @Command
|
||||
*/
|
||||
class NsqCommand extends HyperfCommand
|
||||
{
|
||||
protected $name = 'nsq:pub';
|
||||
|
||||
public function handle()
|
||||
{
|
||||
/** @var Nsq $nsq */
|
||||
$nsq = make(Nsq::class);
|
||||
$topic = 'hyperf';
|
||||
$message = 'This is message at ' . time();
|
||||
$deferTime = 5.0;
|
||||
$nsq->publish($topic, $message, $deferTime);
|
||||
|
||||
$this->line('success', 'info');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### NSQD HTTP API
|
||||
|
||||
> NSQD HTTP API Refer: https://nsq.io/components/nsqd.html
|
||||
|
||||
The component encapsulates the NSQD HTTP API, and you could easily call the NSQD HTTP API by this component.
|
||||
|
||||
For example, when you need to delete a `Topic`, you could execute the following code:
|
||||
|
||||
```php
|
||||
<?php
|
||||
use Hyperf\Utils\ApplicationContext;
|
||||
use Hyperf\Nsq\Nsqd\Topic;
|
||||
|
||||
$container = ApplicationContext::getContainer();
|
||||
|
||||
$client = $container->get(Topic::class);
|
||||
|
||||
$client->delete('hyperf.test');
|
||||
```
|
||||
|
||||
- `Hyperf\Nsq\Api\Topic` class corresponds to `topic` related API;
|
||||
- `Hyperf\Nsq\Api\Channle` class corresponds to `channel` related API;
|
||||
- `Hyperf\Nsq\Api\Api` class corresponds to `ping`、`stats`、`config`、`debug` related API;
|
||||
|
||||
## NSQ Protocol
|
||||
|
||||
> https://nsq.io/clients/tcp_protocol_spec.html
|
||||
|
||||
- Socket
|
||||
|
||||
```plantuml
|
||||
@startuml
|
||||
|
||||
autonumber
|
||||
hide footbox
|
||||
title **Socket**
|
||||
|
||||
participant "Client" as client
|
||||
participant "Server" as server #orange
|
||||
|
||||
activate client
|
||||
activate server
|
||||
|
||||
note right of server: Build Connection
|
||||
client -> server: socket->connect(ip, port)
|
||||
|
||||
...
|
||||
note right of server: Multiple communication send/recv
|
||||
client -> server: socket->send()
|
||||
server-> client: socket->recv()
|
||||
...
|
||||
|
||||
note right of server: Close connection
|
||||
client->server: socket->close()
|
||||
|
||||
deactivate client
|
||||
deactivate server
|
||||
|
||||
@enduml
|
||||
```
|
||||
|
||||
- NSQ Protocol
|
||||
|
||||
```plantuml
|
||||
@startuml
|
||||
|
||||
autonumber
|
||||
hide footbox
|
||||
title **NSQ Protocol**
|
||||
|
||||
participant "Client" as client
|
||||
participant "Server" as server #orange
|
||||
|
||||
activate client
|
||||
activate server
|
||||
|
||||
== connect ==
|
||||
note left of client: after connect, the remaining calls are socket->send/recv
|
||||
client -> server: socket->connect(ip, host)
|
||||
note left of client: protocol version
|
||||
client->server: magic: V2
|
||||
|
||||
== auth ==
|
||||
note left of client: client metadatat
|
||||
client->server: IDENTIFY
|
||||
note right of server: If need auth
|
||||
server->client: auth_required=true
|
||||
client->server: AUTH
|
||||
...
|
||||
|
||||
== pub ==
|
||||
note left of client: Send a message
|
||||
client -> server: PUB <topic_name>
|
||||
note left of client: Send multiple messages
|
||||
client -> server: MPUB
|
||||
note left of client: Send a delay message
|
||||
client -> server: DPUB
|
||||
...
|
||||
|
||||
== sub ==
|
||||
note left of client: client follow a topic by channel
|
||||
note right of server: after SUB, client in RDY 0 stage
|
||||
client -> server: SUB <topic_name> <channel_name>
|
||||
note left of client: Tells server to ready receive <count> messages
|
||||
client -> server: RDY <count>
|
||||
note right of server: server response <count> messages to client
|
||||
server -> client: <count> msg
|
||||
note left of client: Finish a message (indicate successful processing)
|
||||
client -> server: FIN <message_id>
|
||||
note left of client: Re-queue a message (indicate failure to process)
|
||||
client -> server: REQ <message_id> <timeout>
|
||||
note left of client: Reset the timeout for an in-flight message
|
||||
client -> server: TOUCH <message_id>
|
||||
...
|
||||
|
||||
== heartbeat ==
|
||||
server -> client: _heartbeat_
|
||||
note right of server: After 2 unanswered responses, nsqd will timeout and forcefully close a client connection that it has not heard from
|
||||
client -> server: NOP
|
||||
...
|
||||
|
||||
== close ==
|
||||
note left of client: Cleanly close your connection (no more messages are sent)
|
||||
client -> server: CLS
|
||||
note right of server: server response successful
|
||||
server -> client: CLOSE_WAIT
|
||||
|
||||
deactivate client
|
||||
deactivate server
|
||||
|
||||
@enduml
|
||||
```
|
@ -86,7 +86,7 @@ class FooProcess extends AbstractProcess
|
||||
// 您的代码 ...
|
||||
}
|
||||
|
||||
public function isEnable(): bool
|
||||
public function isEnable($server): bool
|
||||
{
|
||||
// 不跟随服务启动一同启动
|
||||
return false;
|
||||
|
@ -8,4 +8,21 @@ Under `PHP-FPM`, you can get the requested parameters through global variables,
|
||||
|
||||
## Classes obtained through the container are singletons
|
||||
|
||||
Through the dependency injection container, all of the in-process persistence is shared by multiple coroutines, so it cannot contain any data that is unique to the request or unique to the coroutine. This type of data is processed through the coroutine context. Please read the [Dependency Injection] (en/di.md) and [Coroutine] (en/coroutine.md) sections carefully.
|
||||
Through the dependency injection container, all of the in-process persistence is shared by multiple coroutines, so it cannot contain any data that is unique to the request or unique to the coroutine. This type of data is processed through the coroutine context. Please read the [Dependency Injection] (en/di.md) and [Coroutine] (en/coroutine.md) sections carefully.
|
||||
|
||||
## Deployment
|
||||
|
||||
> The official Dockerfile has already setup these operations.
|
||||
|
||||
When deploying the production environment, please make sure to enable `scan_cacheable`.
|
||||
|
||||
After enable this configuration, the proxy class and annotation cache will be generated during the first scan, and the cache can be used directly when it is restarted, which greatly optimizes the memory usage and startup time consution. Because the scan stage is skipped, the `Composer Class Map` will be relied upon, so we have to execute `--optimize-autoloader` option of composer command to optimize the class index.
|
||||
|
||||
In summary, update the code of production environment, you need to execute the following commands before restarting the project
|
||||
|
||||
```bash
|
||||
# Optimize the composer class index
|
||||
composer dump-autoload -o
|
||||
# Generate all proxy classes and the annotation cache
|
||||
php bin/hyperf.php
|
||||
```
|
@ -1,54 +1,130 @@
|
||||
# FAQ
|
||||
|
||||
## `Inject` or `Value` annotation does not works
|
||||
|
||||
`2.0` version has changed the mechanism of injection, in the new version, Hyperf will injecting the value of `Inject` and `Value` annotations in the constructor of target class. The following two scenarios may cause injection failure, please pay attention.
|
||||
|
||||
1. The target class have not use `Inject` or `Value` annotations, but the parent class uses `Inject` or `Value` annotations, also the target class has a constructor, but at the same time the parent class constructor is not called by child class.
|
||||
|
||||
This case will cause the target class will not generate the proxy class, and call its own constructor when instantiating, so there is no way to execute the parent class's constructor.
|
||||
So the method `__handlePropertyHandler` in the proxy class of the parent class will not be executed, then the `Inject` or `Value` annotations will not take effect.
|
||||
|
||||
```php
|
||||
class ParentClass {
|
||||
/**
|
||||
* @Inject
|
||||
* @var Service
|
||||
*/
|
||||
protected $value;
|
||||
}
|
||||
|
||||
class Origin extends ParentClass
|
||||
{
|
||||
public function __construct() {}
|
||||
}
|
||||
```
|
||||
|
||||
2. The target class have not use `Inject` or `Value` annotatinos, but `Inject` or `Value` annotations are used in the `Trait` that use by target class.
|
||||
|
||||
This case will cause the target class will not generate the proxy class, so there is no way to execute the `__handlePropertyHandler` in the constructor, then the `Inject` or `Value` annotations of `Trait` will not take effect.
|
||||
|
||||
```php
|
||||
trait OriginTrait {
|
||||
/**
|
||||
* @Inject
|
||||
* @var Service
|
||||
*/
|
||||
protected $value;
|
||||
}
|
||||
|
||||
class Origin
|
||||
{
|
||||
use OriginTrait;
|
||||
}
|
||||
```
|
||||
|
||||
Based on the above two cases, it can be seen that whether the target class generates the proxy class is very important action. Therefore, if you use `Trait` and `parent class` with `Inject` or `Value` annotations, you could just add a `Inject` or `Value` annotations to the target class could solve the above two cases.
|
||||
|
||||
```php
|
||||
|
||||
use Hyperf\Contract\StdoutLoggerInterface;
|
||||
|
||||
trait OriginTrait {
|
||||
/**
|
||||
* @Inject
|
||||
* @var Service
|
||||
*/
|
||||
protected $trait;
|
||||
}
|
||||
|
||||
class ParentClass {
|
||||
/**
|
||||
* @Inject
|
||||
* @var Service
|
||||
*/
|
||||
protected $value;
|
||||
}
|
||||
|
||||
class Origin extends ParentClass
|
||||
{
|
||||
use OriginTrait;
|
||||
|
||||
/**
|
||||
* @Inject
|
||||
* @var StdoutLoggerInterface
|
||||
*/
|
||||
protected $logger;
|
||||
}
|
||||
```
|
||||
|
||||
## Swoole Short Name has not been disabled
|
||||
|
||||
```
|
||||
[ERROR] Swoole short name have to disable before start server, please set swoole.use_shortname = 'Off' into your php.ini.
|
||||
```
|
||||
|
||||
This may be because you set it up as follows
|
||||
|
||||
```
|
||||
// These are all wrong, pay attention to `word case` and `quotes`
|
||||
swoole.use_shortname = 'off'
|
||||
swoole.use_shortname = off
|
||||
swoole.use_shortname = Off
|
||||
// The following is correct
|
||||
swoole.use_shortname = 'Off'
|
||||
```
|
||||
You need to add `swoole.use_shortname ='Off'` configuration in your php.ini configuration file
|
||||
|
||||
> Note that this configuration MUST be configured in php.ini and CANNOT be overridden by the ini_set() function.
|
||||
|
||||
## Proxy class cache
|
||||
|
||||
Once the proxy class cache is generated, it will not be overwritten again. So when you modify the file that has generated the proxy class, you need to manually clean it up.
|
||||
|
||||
The proxy class location in:
|
||||
```
|
||||
runtime/container/proxy/
|
||||
```
|
||||
|
||||
Re-genenrate command
|
||||
```
|
||||
vendor/bin/init-proxy.sh
|
||||
```
|
||||
|
||||
So the command to run unit test can use the following instead
|
||||
```
|
||||
vendor/bin/init-proxy.sh && composer test
|
||||
```
|
||||
|
||||
Similarly, the command to start the server can also use the following instead
|
||||
```
|
||||
vendor/bin/init-proxy.sh && php bin/hyperf.php start
|
||||
```
|
||||
|
||||
## Docker build failure
|
||||
|
||||
Display `wget: error getting response: Connection reset by peer`
|
||||
|
||||
Modify the `Dockerfile`, reinstall `wget`, add the following code:
|
||||
You could also start the server through the following command, turn off the Swoole short name function when executing the PHP command
|
||||
|
||||
```
|
||||
&& apk add wget \
|
||||
```
|
||||
php -d swoole.use_shortname=Off bin/hyperf.php start
|
||||
```
|
||||
|
||||
## The message of async-queue loss
|
||||
|
||||
If you notice that the logical of `handle` method does not executed when using the async-queue component, please check the following situations first:
|
||||
|
||||
1. Is `Redis Server` shared with other project or other peoples, and messages are consumed by other project or other peoples?
|
||||
2. Whether the local process has remnants and is consumed by other processes
|
||||
|
||||
The following provides a foolproof solution:
|
||||
|
||||
1. killall php
|
||||
2. Modify `async-queue` configuration `channel`
|
||||
|
||||
## Shows `Swoole\Error: API must be called in the coroutine` error when using hyperf/amqp component
|
||||
|
||||
You can modify the `close_on_destruct` configuration value to `false` in the `config/autoload/amqp.php` configuration file.
|
||||
|
||||
## When using Swoole 4.5 version and view component, all accesses appears 404
|
||||
|
||||
If you are using Swoole 4.5 version and the view component if there is an 404 problem, you can try to remove the `static_handler_locations` configuration item in the `config/autoload/server.php` file.
|
||||
|
||||
The path under this configuration will be considered as a static file route, so if `/` is configured, all requests will be considered as file paths, resulting in 404.
|
||||
|
||||
## Code does not take effect after modified
|
||||
|
||||
When you encounter the problem that the modified code does not take effect, please execute the following command
|
||||
|
||||
```bash
|
||||
composer dump-autoload -o
|
||||
```
|
||||
|
||||
During the development stage, please DO NOT set `scan_cacheable` configuration value to `true`, it will cause the file to not be scanned again when the `collector cache` exists. In addition, the `Dockerfile` in the official skeleton package has this configuration enabled by default. When developing under the `Docker` environment, please pay attention to this.
|
||||
|
||||
> When the environment variable exists SCAN_CACHEABLE, this configuration cannot be modified in .env file.
|
||||
|
||||
`2.0.0` and `2.0.1`, these two versions, when judging whether the file is modified, there is no judgment that the modification time is equal, so after the file is modified, the cache will be generated immediately (for example, when the `watcher` component is used), as a result, the code cannot take effect in time.
|
173
docs/en/redis.md
173
docs/en/redis.md
@ -6,24 +6,32 @@
|
||||
composer require hyperf/redis
|
||||
```
|
||||
|
||||
## 配置
|
||||
## Configuration
|
||||
|
||||
| 配置项 | 类型 | 默认值 | 备注 |
|
||||
| Config | Type | Default Value | Comment |
|
||||
|:------:|:-------:|:-----------:|:---------:|
|
||||
| host | string | 'localhost' | Redis地址 |
|
||||
| auth | string | 无 | 密码 |
|
||||
| port | integer | 6379 | 端口 |
|
||||
| db | integer | 0 | DB |
|
||||
|
||||
| host | string | 'localhost' | The host of Redis Server |
|
||||
| auth | string | null | The password of Redis Server |
|
||||
| port | integer | 6379 | The port of Redis Server |
|
||||
| db | integer | 0 | The DB of Redis Server |
|
||||
| cluster.enable | boolean | false | Is it cluster mode ? |
|
||||
| cluster.name | string | null | The cluster name |
|
||||
| cluster.seeds | array | [] | The seeds of cluster, format: ['host:port'] |
|
||||
| pool | object | {} | The connection pool |
|
||||
| options | object | {} | The options of Redis Client |
|
||||
```php
|
||||
<?php
|
||||
|
||||
return [
|
||||
'default' => [
|
||||
'host' => env('REDIS_HOST', 'localhost'),
|
||||
'auth' => env('REDIS_AUTH', ''),
|
||||
'port' => (int) env('REDIS_PORT', 6379),
|
||||
'db' => (int) env('REDIS_DB', 0),
|
||||
'cluster' => [
|
||||
'enable' => (bool) env('REDIS_CLUSTER_ENABLE', false),
|
||||
'name' => null,
|
||||
'seeds' => [],
|
||||
],
|
||||
'pool' => [
|
||||
'min_connections' => 1,
|
||||
'max_connections' => 10,
|
||||
@ -37,9 +45,9 @@ return [
|
||||
|
||||
```
|
||||
|
||||
## 使用
|
||||
## Usage
|
||||
|
||||
`hyperf/redis` 实现了 `ext-redis` 代理和连接池,用户可以直接使用\Redis客户端。
|
||||
`hyperf/redis` implemented the proxy of `ext-redis` and the connection pool, you could use `\Redis` class directly.
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -50,9 +58,9 @@ $result = $redis->keys('*');
|
||||
|
||||
```
|
||||
|
||||
## 多库配置
|
||||
## Multi-resource configuration
|
||||
|
||||
有时候在实际使用中,一个 `Redis` 库并不满足需求,一个项目往往需要配置多个库,这个时候,我们就需要修改一下配置文件 `redis.php`,如下:
|
||||
Sometimes, a single `Redis` resource can not meet the needs, and a project often needs to configure multiple resources. At this time, we could modify the configuration file `redis.php` as follows:
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -63,6 +71,11 @@ return [
|
||||
'auth' => env('REDIS_AUTH', ''),
|
||||
'port' => (int) env('REDIS_PORT', 6379),
|
||||
'db' => (int) env('REDIS_DB', 0),
|
||||
'cluster' => [
|
||||
'enable' => (bool) env('REDIS_CLUSTER_ENABLE', false),
|
||||
'name' => null,
|
||||
'seeds' => [],
|
||||
],
|
||||
'pool' => [
|
||||
'min_connections' => 1,
|
||||
'max_connections' => 10,
|
||||
@ -72,7 +85,7 @@ return [
|
||||
'max_idle_time' => (float) env('REDIS_MAX_IDLE_TIME', 60),
|
||||
],
|
||||
],
|
||||
// 增加一个名为 foo 的 Redis 连接池
|
||||
// Added a named `foo` redis connection pool
|
||||
'foo' => [
|
||||
'host' => env('REDIS_HOST', 'localhost'),
|
||||
'auth' => env('REDIS_AUTH', ''),
|
||||
@ -91,9 +104,9 @@ return [
|
||||
|
||||
```
|
||||
|
||||
### 通过代理类使用
|
||||
### Use through proxy class
|
||||
|
||||
我们可以重写一个 `FooRedis` 类并继承 `Hyperf\Redis\Redis` 类,修改 `poolName` 为上述的 `foo`,即可完成对连接池的切换,示例:
|
||||
We could rewrite a `FooRedis` class and inherit the `Hyperf\Redis\Redis` class, and modify the `poolName` property to the above `foo`, to complete the switch of the connection pool, for example:
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -102,29 +115,149 @@ use Hyperf\Redis\Redis;
|
||||
|
||||
class FooRedis extends Redis
|
||||
{
|
||||
// 对应的 Pool 的 key 值
|
||||
// The key value of the corresponding Pool
|
||||
protected $poolName = 'foo';
|
||||
}
|
||||
|
||||
// 通过 DI 容器获取或直接注入当前类
|
||||
// Obtain or directly inject the current class through the DI container
|
||||
$redis = $this->container->get(FooRedis::class);
|
||||
|
||||
$result = $redis->keys('*');
|
||||
|
||||
```
|
||||
|
||||
### 使用工厂类
|
||||
### Use through factory
|
||||
|
||||
在每个库对应一个静态的场景时,通过代理类是一种很好的区分的方法,但有时候需求可能会更加的动态,这时候我们可以通过 `Hyperf\Redis\RedisFactory` 工厂类来动态的传递 `poolName` 来获得对应的连接池的客户端,而无需为每个库创建代理类,示例如下:
|
||||
When each resource corresponds to a static scene, the proxy class is a good way to distinguish the resources, but sometimes the demand may be more dynamic. At this time, we could use the `Hyperf\Redis\RedisFactory` factory class to dynamically pass `poolName` argument to retrieve the client of the corresponding connection pool without creating a proxy class for each resource, for example:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use Hyperf\Redis\RedisFactory;
|
||||
|
||||
// 通过 DI 容器获取或直接注入 RedisFactory 类
|
||||
// Obtain or directly inject the RedisFactory class through the DI container
|
||||
$redis = $this->container->get(RedisFactory::class)->get('foo');
|
||||
|
||||
$result = $redis->keys('*');
|
||||
```
|
||||
|
||||
## Cluster mode
|
||||
|
||||
### Cluster name
|
||||
|
||||
Configure `cluster`, modify `redis.ini`, or modify `Dockerfile`, as follows:
|
||||
|
||||
```
|
||||
# - config PHP
|
||||
&& { \
|
||||
echo "upload_max_filesize=100M"; \
|
||||
echo "post_max_size=108M"; \
|
||||
echo "memory_limit=1024M"; \
|
||||
echo "date.timezone=${TIMEZONE}"; \
|
||||
echo "redis.clusters.seeds = \"mycluster[]=localhost:7000&mycluster[]=localhost:7001\""; \
|
||||
echo "redis.clusters.timeout = \"mycluster=5\""; \
|
||||
echo "redis.clusters.read_timeout = \"mycluster=10\""; \
|
||||
echo "redis.clusters.auth = \"mycluster=password\"";
|
||||
} | tee conf.d/99-overrides.ini \
|
||||
```
|
||||
|
||||
The corresponding PHP configuration is as follows
|
||||
|
||||
```php
|
||||
<?php
|
||||
// ./config/autoload/redis.php
|
||||
// Ignore the other irrelevant configurations
|
||||
return [
|
||||
'default' => [
|
||||
'cluster' => [
|
||||
'enable' => true,
|
||||
'name' => 'mycluster',
|
||||
'seeds' => [],
|
||||
],
|
||||
],
|
||||
];
|
||||
```
|
||||
|
||||
### Seeds
|
||||
|
||||
Of course, it is also available to use `seeds` directly without configuring the `name`, as follows:
|
||||
|
||||
```php
|
||||
<?php
|
||||
// Ignore the other irrelevant configurations
|
||||
return [
|
||||
'default' => [
|
||||
'cluster' => [
|
||||
'enable' => true,
|
||||
'name' => null,
|
||||
'seeds' => [
|
||||
'192.168.1.110:6379',
|
||||
'192.168.1.111:6379',
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
You could define `options` configuration to set the options of Redis Client.
|
||||
|
||||
For example, use PHP Serializer to serialize the result:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
'default' => [
|
||||
'host' => env('REDIS_HOST', 'localhost'),
|
||||
'auth' => env('REDIS_AUTH', null),
|
||||
'port' => (int) env('REDIS_PORT', 6379),
|
||||
'db' => (int) env('REDIS_DB', 0),
|
||||
'pool' => [
|
||||
'min_connections' => 1,
|
||||
'max_connections' => 10,
|
||||
'connect_timeout' => 10.0,
|
||||
'wait_timeout' => 3.0,
|
||||
'heartbeat' => -1,
|
||||
'max_idle_time' => (float) env('REDIS_MAX_IDLE_TIME', 60),
|
||||
],
|
||||
'options' => [
|
||||
Redis::OPT_SERIALIZER => Redis::SERIALIZER_PHP,
|
||||
],
|
||||
],
|
||||
];
|
||||
```
|
||||
|
||||
For example, set the redis client never timeout:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
'default' => [
|
||||
'host' => env('REDIS_HOST', 'localhost'),
|
||||
'auth' => env('REDIS_AUTH', null),
|
||||
'port' => (int) env('REDIS_PORT', 6379),
|
||||
'db' => (int) env('REDIS_DB', 0),
|
||||
'pool' => [
|
||||
'min_connections' => 1,
|
||||
'max_connections' => 10,
|
||||
'connect_timeout' => 10.0,
|
||||
'wait_timeout' => 3.0,
|
||||
'heartbeat' => -1,
|
||||
'max_idle_time' => (float) env('REDIS_MAX_IDLE_TIME', 60),
|
||||
],
|
||||
'options' => [
|
||||
Redis::OPT_READ_TIMEOUT => -1,
|
||||
],
|
||||
],
|
||||
];
|
||||
```
|
||||
|
||||
> Notice that, in some versions of `phpredis` extension, the value type of `options` has to `string`.
|
||||
|
||||
|
@ -1,10 +1,12 @@
|
||||
# 响应
|
||||
# Response
|
||||
|
||||
在 Hyperf 里可通过 `Hyperf\HttpServer\Contract\ResponseInterface` 接口类来注入 `Response` 代理对象对响应进行处理,默认返回 `Hyperf\HttpServer\Response` 对象,该对象可直接调用所有 `Psr\Http\Message\ResponseInterface` 的方法。
|
||||
In Hyperf, you could get the response proxy object by injected `Hyperf\HttpServer\Contract\ResponseInterface` interface, by default, DI container will return an `Hyperf\HttpServer\Response` object, you could directly call all methods of `Psr\Http\Message\ResponseInterface` via this object.
|
||||
|
||||
## 返回 Json 格式
|
||||
> Note that the standard PSR-7 response object is an immutable object. The return value of all methods starts with `with` is a new object and will not modify the value of the original object.
|
||||
|
||||
`Hyperf\HttpServer\Contract\ResponseInterface` 提供了 `json($data)` 方法用于快速返回 `Json` 格式,并设置 `Content-Type` 为 `application/json`,`$data` 接受一个数组或为一个实现了 `Hyperf\Utils\Contracts\Arrayable` 接口的对象。
|
||||
## Return JSON
|
||||
|
||||
You could return a `Json` format content quickly by method `json($data)` of `Hyperf\HttpServer\Contract\ResponseInterface`, and also the `Content-Type` of response object will be set to `application/json`, `$data` accept an array or an object that implemented `Hyperf\Utils\Contracts\Arrayable` interface.
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -25,9 +27,9 @@ class IndexController
|
||||
}
|
||||
```
|
||||
|
||||
## 返回 Xml 格式
|
||||
## Return XML
|
||||
|
||||
`Hyperf\HttpServer\Contract\ResponseInterface` 提供了 `xml($data)` 方法用于快速返回 `XML` 格式,并设置 `Content-Type` 为 `application/xml`,`$data` 接受一个数组或为一个实现了 `Hyperf\Utils\Contracts\Xmlable` 接口的对象。
|
||||
You could return a `XML` format content quickly by method `xml($data)` of `Hyperf\HttpServer\Contract\ResponseInterface`, and also the `Content-Type` of response object will be set to `application/xml`, `$data` accept an array or an object that implemented `Hyperf\Utils\Contracts\Xmlable` interface.
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -48,9 +50,9 @@ class IndexController
|
||||
}
|
||||
```
|
||||
|
||||
## 返回 Raw 格式
|
||||
## Return the raw content
|
||||
|
||||
`Hyperf\HttpServer\Contract\ResponseInterface` 提供了 `raw($data)` 方法用于快速返回 `raw` 格式,并设置 `Content-Type` 为 `plain/text`,`$data` 接受一个字符串或为一个实现了 `__toString()` 方法的对象。
|
||||
You could return the raw content quickly by method `raw($data)` of `Hyperf\HttpServer\Contract\ResponseInterface`, and also the `Content-Type` of response object will be set to `plain/text`, `$data` accept a string or an object that implemented `__toString()` method.
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -68,21 +70,21 @@ class IndexController
|
||||
}
|
||||
```
|
||||
|
||||
## 返回视图
|
||||
## Return view
|
||||
|
||||
Hyperf 暂不支持视图返回,欢迎社区贡献相关的 PR。
|
||||
Please refer to [View](zh-cn/view.md).
|
||||
|
||||
## 重定向
|
||||
## Redirection
|
||||
|
||||
`Hyperf\HttpServer\Contract\ResponseInterface` 提供了 `redirect(string $toUrl, int $status = 302, string $schema = 'http')` 返回一个已设置重定向状态的 `Psr7ResponseInterface` 对象。
|
||||
`Hyperf\HttpServer\Contract\ResponseInterface` provides `redirect(string $toUrl, int $status = 302, string $schema = 'http')` method to return an `Psr7ResponseInterface` object which has already setup redirection status.
|
||||
|
||||
`redirect` 方法:
|
||||
`redirect`:
|
||||
|
||||
| 参数 | 类型 | 默认值 | 备注 |
|
||||
|:-------------------:|:------:|:---------------:|:------------------:|
|
||||
| toUrl | string | 无 | 如果参数不存在 `http://` 或 `https://` 则根据当前服务的 Host 自动拼接对应的 URL,且根据 `$schema` 参数拼接协议 |
|
||||
| status | int | 302 | 响应状态码 |
|
||||
| schema | string | http | 当 `$toUrl` 不存在 `http://` 或 `https://` 时生效,仅可传递 `http` 或 `https` |
|
||||
| Arguments | Type | Default Value | Comment |
|
||||
|:------:|:------:|:------:|:--------------------------------------------------------------------------------------------------------------:|
|
||||
| toUrl | string | null | If the argument does not starts with `http://` or `https://`, the corresponding URL will be automatically spliced according to the Host of the current server, and the splicing protocol according to the `$schema` argument |
|
||||
| status | int | 302 | Status code of Response |
|
||||
| schema | string | http | Effective when `$toUrl` does not starts with `http://` or `https://`, only `http` or `https` are available |
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -95,13 +97,13 @@ class IndexController
|
||||
{
|
||||
public function redirect(ResponseInterface $response): Psr7ResponseInterface
|
||||
{
|
||||
// redirect() 方法返回的是一个 Psr\Http\Message\ResponseInterface 对象,需再 return 回去
|
||||
// redirect() method will return an Psr\Http\Message\ResponseInterface object, needs to return the object.
|
||||
return $response->redirect('/anotherUrl');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Cookie 设置
|
||||
## Cookie
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -109,7 +111,7 @@ namespace App\Controller;
|
||||
|
||||
use Hyperf\HttpServer\Contract\ResponseInterface;
|
||||
use Psr\Http\Message\ResponseInterface as Psr7ResponseInterface;
|
||||
use Swoft\Http\Message\Cookie\Cookie;
|
||||
use Hyperf\HttpMessage\Cookie\Cookie;
|
||||
|
||||
class IndexController
|
||||
{
|
||||
@ -121,8 +123,35 @@ class IndexController
|
||||
}
|
||||
```
|
||||
|
||||
## Gzip 压缩
|
||||
## Gzip Compression
|
||||
|
||||
## 分块传输编码 Chunk
|
||||
## Chunk
|
||||
|
||||
## 返回文件下载
|
||||
## File Download
|
||||
|
||||
`Hyperf\HttpServer\Contract\ResponseInterface` provides `download(string $file, string $name = '')` method to return an `Psr7ResponseInterface` object which already setup the file download status.
|
||||
If the request contains `if-match` or `if-none-match` header, Hyperf will also compare it with the `ETag` according to the protocol standard, and if they match, it will return a response with a `304` status code.
|
||||
|
||||
`download`:
|
||||
|
||||
| Arguments | Type | Default Value | Comment |
|
||||
|:----:|:------:|:------:|:-------------------------------------------------------------------:|
|
||||
| file | string | null | To return to the absolute path of the downloaded file, use the `BASE_PATH` constant to locate the root directory of the project |
|
||||
| name | string | null | The file name of the client download file, if it is empty, the original name of the downloaded file will be used |
|
||||
|
||||
|
||||
```php
|
||||
<?php
|
||||
namespace App\Controller;
|
||||
|
||||
use Hyperf\HttpServer\Contract\ResponseInterface;
|
||||
use Psr\Http\Message\ResponseInterface as Psr7ResponseInterface;
|
||||
|
||||
class IndexController
|
||||
{
|
||||
public function index(ResponseInterface $response): Psr7ResponseInterface
|
||||
{
|
||||
return $response->download(BASE_PATH . '/public/file.csv', 'filename.csv');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -72,7 +72,13 @@
|
||||
* [Tracing](en/tracer.md)
|
||||
* [Metric](en/metric.md)
|
||||
* [Retry](en/retry.md)
|
||||
* [Nacos](en/nacos.md)
|
||||
* [Snowflake](en/snowflake.md)
|
||||
|
||||
* Server
|
||||
|
||||
* [Tcp Server](en/tcp-server.md)
|
||||
* [WebSocket Server](en/websocket-server.md)
|
||||
* [Socket.io](en/socketio-server.md)
|
||||
|
||||
* Message Queue
|
||||
|
||||
@ -81,35 +87,37 @@
|
||||
* [Nats](en/nats.md)
|
||||
* [NSQ](en/nsq.md)
|
||||
|
||||
* Other Components
|
||||
|
||||
* [Connection Pool](en/pool.md)
|
||||
* Clients
|
||||
|
||||
* [Redis Client](en/redis.md)
|
||||
* [Guzzle HTTP Client](en/guzzle.md)
|
||||
* [Elasticsearch Client](en/elasticsearch.md)
|
||||
* [Consul Client](en/consul.md)
|
||||
* [ETCD Client](en/etcd.md)
|
||||
* [WebSocket Server](en/websocket-server.md)
|
||||
* [WebSocket Client](en/websocket-client.md)
|
||||
* [Socket.io](en/socketio-server.md)
|
||||
* [Nacos](en/nacos.md)
|
||||
* [Jet](en/jet.md)
|
||||
|
||||
* Other Components
|
||||
|
||||
* [Connection Pool](en/pool.md)
|
||||
* [Custom Process](en/process.md)
|
||||
* [Dev Tool](en/devtool.md)
|
||||
* [Utils](en/utils.md)
|
||||
* [Rate Limit](en/rate-limit.md)
|
||||
* [Swoole Tracker](en/swoole-tracker.md)
|
||||
* [Crontab](en/crontab.md)
|
||||
* [Task](en/task.md)
|
||||
* [Enum](en/constants.md)
|
||||
* [Snowflake](en/snowflake.md)
|
||||
* [Signal Manager](en/signal.md)
|
||||
* [ReactiveX](en/reactive-x.md)
|
||||
* [Watcher](en/watcher.md)
|
||||
* [Dev Tool](en/devtool.md)
|
||||
* [Swoole Tracker](en/swoole-tracker.md)
|
||||
|
||||
* Application Deployment
|
||||
* Deployment
|
||||
|
||||
* [Build Docker Swarm cluster](en/tutorial/docker-swarm.md)
|
||||
* [Build DaoCloud Devops](en/tutorial/daocloud.md)
|
||||
* [Deploy Supervisor](en/tutorial/supervisor.md)
|
||||
* [Deploy by Supervisor](en/tutorial/supervisor.md)
|
||||
|
||||
* Awesome Hyperf
|
||||
|
||||
@ -119,6 +127,7 @@
|
||||
|
||||
* [Introduction](en/component-guide/intro.md)
|
||||
* [Create a new component](en/component-guide/create.md)
|
||||
* [ConfigProvider](en/component-guide/configprovider.md)
|
||||
|
||||
* Upgrade Guide
|
||||
|
||||
|
@ -97,7 +97,7 @@ WORKDIR /opt/www
|
||||
|
||||
RUN composer install --no-dev \
|
||||
&& composer dump-autoload -o \
|
||||
&& php /opt/www/bin/hyperf.php di:init-proxy
|
||||
&& php /opt/www/bin/hyperf.php
|
||||
|
||||
EXPOSE 9501
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||
<meta name="description" content="Hyperf框架官方文档">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
|
||||
<link rel="shortcut icon" href="//hyperf.wiki/2.0/favicon.ico" />
|
||||
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify/themes/vue.css">
|
||||
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.css">
|
||||
<style>
|
||||
@ -18,7 +19,7 @@
|
||||
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script src="//cdn.jsdelivr.net/gh/sy-records/staticfile/js/docsify/docsify.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify/lib/docsify.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/prismjs/components/prism-php.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify-edit-on-github/index.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
|
||||
@ -54,7 +55,8 @@
|
||||
'/zh-hk/': '輸入關鍵詞搜索',
|
||||
'/zh-tw/': '輸入關鍵詞搜索',
|
||||
'/': '输入关键词搜索'
|
||||
}
|
||||
},
|
||||
pathNamespaces: ['/zh-cn', '/zh-tw', '/zh-hk', '/en']
|
||||
},
|
||||
alias: {
|
||||
'/summary.md': './zh-cn/summary.md'
|
||||
@ -78,7 +80,7 @@
|
||||
}
|
||||
</script>
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify-copy-code"></script>
|
||||
<script src="//cdn.jsdelivr.net/gh/sy-records/staticfile/js/docsify/search.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/search.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify-plantuml/dist/docsify-plantuml.min.js"></script>
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/zoom-image.min.js"></script>
|
||||
<script type="text/javascript">var cnzz_protocol = (("https:" == document.location.protocol) ? "https://" : "http://");document.write(unescape("%3Cspan style='display:none;' id='cnzz_stat_icon_1278274447'%3E%3C/span%3E%3Cscript src='" + cnzz_protocol + "v1.cnzz.com/z_stat.php%3Fid%3D1278274447' type='text/javascript'%3E%3C/script%3E"));</script>
|
||||
|
@ -190,6 +190,7 @@ use Hyperf\Contract\StdoutLoggerInterface;
|
||||
use Hyperf\ExceptionHandler\Formatter\FormatterInterface;
|
||||
use Hyperf\Utils;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Swoole\Coroutine as SwooleCoroutine;
|
||||
|
||||
class Coroutine
|
||||
@ -227,7 +228,10 @@ class Coroutine
|
||||
$id = Utils\Coroutine::id();
|
||||
$result = SwooleCoroutine::create(function () use ($callable, $id) {
|
||||
try {
|
||||
Utils\Context::copy($id);
|
||||
// 按需复制,禁止复制 Socket,不然会导致 Socket 跨协程调用从而报错。
|
||||
Utils\Context::copy($id, [
|
||||
ServerRequestInterface::class,
|
||||
]);
|
||||
call($callable);
|
||||
} catch (Throwable $throwable) {
|
||||
if ($this->formatter) {
|
||||
@ -261,7 +265,7 @@ declare(strict_types=1);
|
||||
*/
|
||||
namespace Hyperf\Utils;
|
||||
|
||||
use App\Kernel\Context\Coroutine as BCoroutine;
|
||||
use App\Kernel\Context\Coroutine as Co;
|
||||
use Swoole\Coroutine as SwooleCoroutine;
|
||||
use Hyperf\Utils\ApplicationContext;
|
||||
|
||||
@ -314,7 +318,7 @@ class Coroutine
|
||||
*/
|
||||
public static function create(callable $callable): int
|
||||
{
|
||||
return ApplicationContext::getContainer()->get(BCoroutine::class)->create($callable);
|
||||
return ApplicationContext::getContainer()->get(Co::class)->create($callable);
|
||||
}
|
||||
|
||||
public static function inCoroutine(): bool
|
||||
|
@ -422,7 +422,7 @@ use Hyperf\Process\Annotation\Process;
|
||||
/**
|
||||
* @Process()
|
||||
*/
|
||||
class ConsumerProcess extends ConsumerProcess
|
||||
class OtherConsumerProcess extends ConsumerProcess
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
@ -445,6 +445,8 @@ return $driver->push(new ExampleJob());
|
||||
|
||||
异步队列在终止时,如果正在进行消费逻辑,可能会导致出现错误。框架提供了 `DriverStopHandler` ,可以让异步队列进程安全关闭。
|
||||
|
||||
> 当前信号处理器并不适配于 CoroutineServer,如有需要请自行实现
|
||||
|
||||
安装信号处理器
|
||||
|
||||
```
|
||||
|
@ -3,6 +3,8 @@
|
||||
所有官方提供的组件库均已进行协程化处理,可安全地在 Hyperf 内或其它协程框架内使用,基于 Hyperf 的开放性和可扩展性,社区可对此开发或适配各种各样的组件,得益于此,Hyperf 将存在着无限的可能性。
|
||||
本页将收录各个适配了 Hyperf 的协程组件 和 已经经过验证可安全地用于协程下的常用库,以便您快速的从中选择合适的组件完成您的需求。
|
||||
|
||||
> 组件顺序以收录时间排序
|
||||
|
||||
## 如何提交我的组件?
|
||||
|
||||
如果您开发的协程组件适配了 Hyperf,那么您可以直接对 [hyperf/hyperf](https://github.com/hyperf/hyperf) 项目的 `master` 分支发起您的 `Pull Request`,也就是更改当前页`(zh-cn/awesome-components.md)`。
|
||||
|
@ -118,7 +118,7 @@ use Hyperf\Cache\Annotation\Cacheable;
|
||||
class DemoService
|
||||
{
|
||||
/**
|
||||
* @Cacheable(prefix="cache", value="_#{id}", listener="DemoServiceDelete")
|
||||
* @Cacheable(prefix="cache", value="_#{id}", listener="user-update")
|
||||
*/
|
||||
public function getCache(int $id)
|
||||
{
|
||||
|
@ -1,5 +1,71 @@
|
||||
# 版本更新记录
|
||||
|
||||
# v2.0.9 - 2020-08-31
|
||||
|
||||
## 新增
|
||||
|
||||
- [#2331](https://github.com/hyperf/hyperf/pull/2331) [hyperf/nacos](https://github.com/hyperf/nacos) 组件增加授权接口。
|
||||
- [#2331](https://github.com/hyperf/hyperf/pull/2331) [hyperf/nacos](https://github.com/hyperf/nacos) 组件增加 `nacos.enable` 配置,用于控制是否启用 `Nacos` 服务。
|
||||
- [#2331](https://github.com/hyperf/hyperf/pull/2331) [hyperf/nacos](https://github.com/hyperf/nacos) 组件增加配置合并类型,默认使用全量覆盖。
|
||||
- [#2377](https://github.com/hyperf/hyperf/pull/2377) 为 gRPC 客户端 的 request 增加 `ts` 请求头,以兼容 Node.js gRPC server 等。
|
||||
- [#2384](https://github.com/hyperf/hyperf/pull/2384) 新增助手函数 `optional()`,以创建 `Hyperf\Utils\Optional` 对象或更方便 Optional 的使用。
|
||||
|
||||
## 修改
|
||||
|
||||
- [#2331](https://github.com/hyperf/hyperf/pull/2331) 修复 [hyperf/nacos](https://github.com/hyperf/nacos) 组件,服务或配置不存在时,会抛出异常的问题。
|
||||
- [#2356](https://github.com/hyperf/hyperf/pull/2356) [#2368](https://github.com/hyperf/hyperf/pull/2368) 修复 `pid_file` 被用户修改后,命令行 `server:start` 启动失败的问题。
|
||||
- [#2358](https://github.com/hyperf/hyperf/pull/2358) 修复验证器规则 `digits` 不支持 `int` 类型的问题。
|
||||
|
||||
## 优化
|
||||
|
||||
- [#2359](https://github.com/hyperf/hyperf/pull/2359) 优化自定义进程,在协程风格服务下,可以更加友好的停止。
|
||||
- [#2363](https://github.com/hyperf/hyperf/pull/2363) 优化 [hyperf/di](https://github.com/hyperf/di) 组件,使其不需要依赖 [hyperf/config](https://github.com/hyperf/config) 组件。
|
||||
- [#2373](https://github.com/hyperf/hyperf/pull/2373) 优化 [hyperf/validation](https://github.com/hyperf/validation) 组件的异常捕获器,使其返回 `Response` 时,自动添加 `content-type` 头。
|
||||
|
||||
|
||||
# v2.0.8 - 2020-08-24
|
||||
|
||||
## 新增
|
||||
|
||||
- [#2334](https://github.com/hyperf/hyperf/pull/2334) 新增更加友好的数组递归合并方法 `Arr::merge`。
|
||||
- [#2335](https://github.com/hyperf/hyperf/pull/2335) 新增 `Hyperf/Utils/Optional`,它可以接受任意参数,并允许访问该对象上的属性或调用其方法,即使给定的对象为 `null`,也不会引发错误。
|
||||
- [#2336](https://github.com/hyperf/hyperf/pull/2336) 新增 `RedisNsqAdapter`,它通过 `NSQ` 发布消息,使用 `Redis` 记录房间信息。
|
||||
|
||||
## 修复
|
||||
|
||||
- [#2338](https://github.com/hyperf/hyperf/pull/2338) 修复文件系统使用 `S3` 适配器时,文件是否存在的逻辑与预期不符的 BUG。
|
||||
- [#2340](https://github.com/hyperf/hyperf/pull/2340) 修复 `__FUNCTION__` 和 `__METHOD__` 魔术方法无法在被 `AOP` 重写的方法里正常工作的 BUG。
|
||||
|
||||
## 优化
|
||||
|
||||
- [#2319](https://github.com/hyperf/hyperf/pull/2319) 优化 `ResolverDispatcher` ,使项目发生循环依赖时,可以提供更加友好的错误提示。
|
||||
|
||||
# v2.0.7 - 2020-08-17
|
||||
|
||||
## 新增
|
||||
|
||||
- [#2307](https://github.com/hyperf/hyperf/pull/2307) [#2312](https://github.com/hyperf/hyperf/pull/2312) [hyperf/nsq](https://github.com/hyperf/nsq) 组件,新增 `NSQD` 的 `HTTP` 客户端。
|
||||
|
||||
## 修复
|
||||
|
||||
- [#2275](https://github.com/hyperf/hyperf/pull/2275) 修复配置中心,拉取配置进程会出现阻塞的 BUG。
|
||||
- [#2276](https://github.com/hyperf/hyperf/pull/2276) 修复 `Apollo` 配置中心,当配置没有变更时,会清除所有本地配置项的 BUG。
|
||||
- [#2280](https://github.com/hyperf/hyperf/pull/2280) 修复 `Interface` 的方法会被 `AOP` 重写,导致启动报错的 BUG。
|
||||
- [#2281](https://github.com/hyperf/hyperf/pull/2281) 当使用 `Task` 组件,且没有启动协程时,`Signal` 组件会导致启动报错的 BUG。
|
||||
- [#2304](https://github.com/hyperf/hyperf/pull/2304) 修复当使用 `SocketIOServer` 的内存适配器,删除 `sid` 时,会导致死循环的 BUG。
|
||||
- [#2309](https://github.com/hyperf/hyperf/pull/2309) 修复 `JsonRpcHttpTransporter` 无法设置自定义超时时间的 BUG。
|
||||
|
||||
# v2.0.6 - 2020-08-10
|
||||
|
||||
## 新增
|
||||
|
||||
- [#2125](https://github.com/hyperf/hyperf/pull/2125) 新增 [hyperf/jet](https://github.com/hyperf/jet) 组件。`Jet` 是一个统一模型的 RPC 客户端,内置 JSONRPC 协议的适配,该组件可适用于所有的 `PHP (>= 7.2)` 环境,包括 PHP-FPM 和 Swoole 或 Hyperf。
|
||||
|
||||
## 修复
|
||||
|
||||
- [#2236](https://github.com/hyperf/hyperf/pull/2236) 修复 `Nacos` 使用负载均衡器选择节点失败的 BUG。
|
||||
- [#2242](https://github.com/hyperf/hyperf/pull/2242) 修复 `watcher` 组件会重复收集多次注解的 BUG。
|
||||
|
||||
# v2.0.5 - 2020-08-03
|
||||
|
||||
## 新增
|
||||
|
@ -2,17 +2,19 @@
|
||||
|
||||
我们提供了 `QQ 群` 和 `微信群` 两种沟通途径,非本页面提供的其它交流途径均非官方行为。
|
||||
|
||||
## QQ 群
|
||||
## QQ 交流群
|
||||
|
||||
Hyperf 交流群(已满): `862099724`
|
||||
Hyperf 交流 2 群: `811414891`
|
||||
|
||||
## 微信群
|
||||
## 微信交流群
|
||||
|
||||
由于微信群无法直接加入,故可先加下方二维码好友,并声明目的,再拉您入群。
|
||||
|
||||
## Contributor 群
|
||||
|
||||
为了更好的发展 Hyperf 的社区,我们专门为 Hyperf Contributor 提供了一个微信群,以便我们对 Pull Request 或迭代计划进行更详细的探讨,由于微信群无法直接加入,故可先加下方二维码好友,并声明目的且带上您已经被 Merged 的 Pull Request,再拉您入群。
|
||||
|
||||
![wechat](imgs/wechat.jpg ':size=375')
|
||||
|
||||
## Community 钉钉群
|
||||
|
||||
为了更好的发展 Hyperf 的开源社区,以及帮助您更容易参与进来,我们提供了 Hyperf Community 钉钉群,以便社区对 Pull Request 或迭代计划进行更详细的探讨,欢迎希望参与进 Hyperf 开源事业的您加入。
|
||||
|
||||
钉钉群号:34538367
|
||||
|
@ -3,145 +3,47 @@
|
||||
`Hyperf` 官方提供了工具来快速创建组件包。
|
||||
|
||||
```
|
||||
# 创建适配 Hyperf 最新版本的组件包
|
||||
composer create-project hyperf/component-creater your_component dev-master
|
||||
|
||||
# 创建适配 Hyperf 1.1 版本的组件包
|
||||
composer create-project hyperf/component-creater your_component "1.1.*"
|
||||
```
|
||||
|
||||
执行结果如下:
|
||||
## 在项目中使用未发布的组件包
|
||||
|
||||
假设项目目录如下
|
||||
|
||||
```
|
||||
$ composer create-project hyperf/component-creater your_component dev-master
|
||||
Installing hyperf/component-creater (dev-master 2a626139a08be9cc3b23e9f03592ccf1b7d3158a)
|
||||
- Installing hyperf/component-creater (dev-master 2a62613): Cloning 2a626139a0 from cache
|
||||
Created project in your_component
|
||||
> Installer\Script::install
|
||||
Setting up optional packages
|
||||
What is your component name (hyperf/demo): sample/component
|
||||
What is your component license (MIT) : MIT
|
||||
What is your component description : Sample Component
|
||||
What is your namespace (Sample\Component): Sample\Component
|
||||
Removing installer development dependencies
|
||||
|
||||
Do you want to use hyperf/framework component ?
|
||||
[1] yes
|
||||
[n] None of the above
|
||||
Make your selection or type a composer package name and version (n): 1
|
||||
- Adding package hyperf/framework (1.0.*)
|
||||
|
||||
Do you want to use hyperf/di component ?
|
||||
[1] yes
|
||||
[n] None of the above
|
||||
Make your selection or type a composer package name and version (n): 1
|
||||
- Adding package hyperf/di (1.0.*)
|
||||
Remove installer
|
||||
Adding .gitattributes
|
||||
Removing Expressive installer classes, configuration, tests and docs
|
||||
Loading composer repositories with package information
|
||||
Updating dependencies (including require-dev)
|
||||
Package operations: 85 installs, 0 updates, 0 removals
|
||||
- Installing ocramius/package-versions (1.4.0): Loading from cache
|
||||
- Installing swoole/ide-helper (dev-master 9de6d57): Cloning 9de6d57310 from cache
|
||||
- Installing doctrine/inflector (v1.3.0): Loading from cache
|
||||
- Installing psr/log (1.1.0): Loading from cache
|
||||
- Installing psr/event-dispatcher (1.0.0): Loading from cache
|
||||
- Installing psr/container (1.0.0): Loading from cache
|
||||
- Installing hyperf/contract (v1.0.6): Loading from cache
|
||||
- Installing hyperf/utils (v1.0.6): Loading from cache
|
||||
- Installing psr/http-message (1.0.1): Loading from cache
|
||||
- Installing fig/http-message-util (1.1.3): Loading from cache
|
||||
- Installing hyperf/framework (v1.0.6): Loading from cache
|
||||
- Installing psr/http-server-handler (1.0.1): Loading from cache
|
||||
- Installing psr/http-server-middleware (1.0.1): Loading from cache
|
||||
- Installing hyperf/dispatcher (v1.0.6): Loading from cache
|
||||
- Installing hyperf/di (v1.0.6): Loading from cache
|
||||
- Installing hyperf/event (v1.0.5): Loading from cache
|
||||
- Installing doctrine/instantiator (1.2.0): Loading from cache
|
||||
- Installing php-di/phpdoc-reader (2.1.0): Loading from cache
|
||||
- Installing symfony/finder (v4.3.3): Loading from cache
|
||||
- Installing doctrine/lexer (1.0.2): Loading from cache
|
||||
- Installing doctrine/annotations (v1.6.1): Loading from cache
|
||||
- Installing nikic/php-parser (v4.2.2): Loading from cache
|
||||
- Installing symfony/service-contracts (v1.1.5): Loading from cache
|
||||
- Installing symfony/polyfill-php73 (v1.11.0): Loading from cache
|
||||
- Installing symfony/polyfill-mbstring (v1.11.0): Loading from cache
|
||||
- Installing symfony/console (v4.3.3): Loading from cache
|
||||
- Installing symfony/stopwatch (v4.3.3): Loading from cache
|
||||
- Installing symfony/process (v4.3.3): Loading from cache
|
||||
- Installing symfony/polyfill-php72 (v1.11.0): Loading from cache
|
||||
- Installing paragonie/random_compat (v9.99.99): Loading from cache
|
||||
- Installing symfony/polyfill-php70 (v1.11.0): Loading from cache
|
||||
- Installing symfony/options-resolver (v4.3.3): Loading from cache
|
||||
- Installing symfony/polyfill-ctype (v1.11.0): Loading from cache
|
||||
- Installing symfony/filesystem (v4.3.3): Loading from cache
|
||||
- Installing symfony/event-dispatcher-contracts (v1.1.5): Loading from cache
|
||||
- Installing symfony/event-dispatcher (v4.3.3): Loading from cache
|
||||
- Installing php-cs-fixer/diff (v1.3.0): Loading from cache
|
||||
- Installing composer/xdebug-handler (1.3.3): Loading from cache
|
||||
- Installing composer/semver (1.5.0): Loading from cache
|
||||
- Installing friendsofphp/php-cs-fixer (v2.15.1): Loading from cache
|
||||
- Installing hyperf/server (v1.0.6): Loading from cache
|
||||
- Installing zendframework/zend-stdlib (3.2.1): Loading from cache
|
||||
- Installing zendframework/zend-mime (2.7.1): Loading from cache
|
||||
- Installing hyperf/http-message (v1.0.6): Loading from cache
|
||||
- Installing hyperf/exception-handler (v1.0.1): Loading from cache
|
||||
- Installing nikic/fast-route (v1.3.0): Loading from cache
|
||||
- Installing hyperf/http-server (v1.0.6): Loading from cache
|
||||
- Installing sebastian/version (2.0.1): Loading from cache
|
||||
- Installing sebastian/resource-operations (2.0.1): Loading from cache
|
||||
- Installing sebastian/recursion-context (3.0.0): Loading from cache
|
||||
- Installing sebastian/object-reflector (1.1.1): Loading from cache
|
||||
- Installing sebastian/object-enumerator (3.0.3): Loading from cache
|
||||
- Installing sebastian/global-state (2.0.0): Loading from cache
|
||||
- Installing sebastian/exporter (3.1.0): Loading from cache
|
||||
- Installing sebastian/environment (4.2.2): Loading from cache
|
||||
- Installing sebastian/diff (3.0.2): Loading from cache
|
||||
- Installing sebastian/comparator (3.0.2): Loading from cache
|
||||
- Installing phpunit/php-timer (2.1.2): Loading from cache
|
||||
- Installing phpunit/php-text-template (1.2.1): Loading from cache
|
||||
- Installing phpunit/php-file-iterator (2.0.2): Loading from cache
|
||||
- Installing theseer/tokenizer (1.1.3): Loading from cache
|
||||
- Installing sebastian/code-unit-reverse-lookup (1.0.1): Loading from cache
|
||||
- Installing phpunit/php-token-stream (3.1.0): Loading from cache
|
||||
- Installing phpunit/php-code-coverage (6.1.4): Loading from cache
|
||||
- Installing webmozart/assert (1.4.0): Loading from cache
|
||||
- Installing phpdocumentor/reflection-common (1.0.1): Loading from cache
|
||||
- Installing phpdocumentor/type-resolver (0.4.0): Loading from cache
|
||||
- Installing phpdocumentor/reflection-docblock (4.3.1): Loading from cache
|
||||
- Installing phpspec/prophecy (1.8.1): Loading from cache
|
||||
- Installing phar-io/version (2.0.1): Loading from cache
|
||||
- Installing phar-io/manifest (1.0.3): Loading from cache
|
||||
- Installing myclabs/deep-copy (1.9.1): Loading from cache
|
||||
- Installing phpunit/phpunit (7.5.14): Loading from cache
|
||||
- Installing hyperf/testing (v1.0.2): Loading from cache
|
||||
- Installing phpstan/phpdoc-parser (0.3.5): Loading from cache
|
||||
- Installing nette/utils (v3.0.1): Loading from cache
|
||||
- Installing nette/finder (v2.5.0): Loading from cache
|
||||
- Installing nette/robot-loader (v3.2.0): Loading from cache
|
||||
- Installing nette/schema (v1.0.0): Loading from cache
|
||||
- Installing nette/php-generator (v3.2.3): Loading from cache
|
||||
- Installing nette/neon (v3.0.0): Loading from cache
|
||||
- Installing nette/di (v3.0.0): Loading from cache
|
||||
- Installing nette/bootstrap (v3.0.0): Loading from cache
|
||||
- Installing jean85/pretty-package-versions (1.2): Loading from cache
|
||||
- Installing phpstan/phpstan (0.10.8): Loading from cache
|
||||
hyperf/utils suggests installing symfony/var-dumper (Required to use the dd function (^4.1).)
|
||||
hyperf/framework suggests installing hyperf/command (Required to use Command annotation.)
|
||||
hyperf/di suggests installing hyperf/config (Require this component for annotation scan progress to retrieve the scan path.)
|
||||
symfony/service-contracts suggests installing symfony/service-implementation
|
||||
symfony/console suggests installing symfony/lock
|
||||
paragonie/random_compat suggests installing ext-libsodium (Provides a modern crypto API that can be used to generate random bytes.)
|
||||
symfony/event-dispatcher suggests installing symfony/dependency-injection
|
||||
symfony/event-dispatcher suggests installing symfony/http-kernel
|
||||
friendsofphp/php-cs-fixer suggests installing php-cs-fixer/phpunit-constraint-isidenticalstring (For IsIdenticalString constraint.)
|
||||
friendsofphp/php-cs-fixer suggests installing php-cs-fixer/phpunit-constraint-xmlmatchesxsd (For XmlMatchesXsd constraint.)
|
||||
zendframework/zend-mime suggests installing zendframework/zend-mail (Zend\Mail component)
|
||||
sebastian/global-state suggests installing ext-uopz (*)
|
||||
phpunit/php-code-coverage suggests installing ext-xdebug (^2.6.0)
|
||||
phpunit/phpunit suggests installing phpunit/php-invoker (^2.0)
|
||||
phpunit/phpunit suggests installing ext-xdebug (*)
|
||||
nette/bootstrap suggests installing tracy/tracy (to use Configurator::enableTracy())
|
||||
Writing lock file
|
||||
Generating autoload files
|
||||
ocramius/package-versions: Generating version class...
|
||||
ocramius/package-versions: ...done generating version class
|
||||
Do you want to remove the existing VCS (.git, .svn..) history? [Y,n]? Y
|
||||
/opt/project // 项目目录
|
||||
/opt/your_component // 组件包目录
|
||||
```
|
||||
|
||||
假设组件名为 `your_component/your_component`
|
||||
|
||||
修改 /opt/project/composer.json
|
||||
|
||||
> 以下省略其他不相干的配置
|
||||
|
||||
```json
|
||||
{
|
||||
"require": {
|
||||
"your_component/your_component": "dev-master"
|
||||
},
|
||||
"repositories": {
|
||||
"your_component": {
|
||||
"type": "path",
|
||||
"url": "/opt/your_component"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
最后在目录 `/opt/project` 中执行 `composer update -o` 即可。
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -135,3 +135,161 @@ return [
|
||||
- Hyperf\Database\Commands\Ast\ModelRewriteTimestampsVisitor
|
||||
|
||||
此 `Visitor` 可以根据 `created_at` 和 `updated_at` 自动判断,是否启用默认记录 `创建和修改时间` 的功能。
|
||||
|
||||
## 覆盖 Visitor
|
||||
|
||||
Hyperf 框架中,当使用 `gen:model` 时,默认会将 `decimal` 转化成为 `float`。如下:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Model;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property int $count
|
||||
* @property float $float_num // decimal
|
||||
* @property string $str
|
||||
* @property string $json
|
||||
* @property \Carbon\Carbon $created_at
|
||||
* @property \Carbon\Carbon $updated_at
|
||||
*/
|
||||
class UserExt extends Model
|
||||
{
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'user_ext';
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = ['id', 'count', 'float_num', 'str', 'json', 'created_at', 'updated_at'];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast to native types.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = ['id' => 'integer', 'count' => 'integer', 'float_num' => 'float', 'created_at' => 'datetime', 'updated_at' => 'datetime'];
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
这时候,我们就可以通过重写 `ModelUpdateVisitor`,修改这一特性。
|
||||
|
||||
```php
|
||||
<?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 App\Kernel\Visitor;
|
||||
|
||||
use Hyperf\Database\Commands\Ast\ModelUpdateVisitor as Visitor;
|
||||
use Hyperf\Utils\Str;
|
||||
|
||||
class ModelUpdateVisitor extends Visitor
|
||||
{
|
||||
protected function formatDatabaseType(string $type): ?string
|
||||
{
|
||||
switch ($type) {
|
||||
case 'tinyint':
|
||||
case 'smallint':
|
||||
case 'mediumint':
|
||||
case 'int':
|
||||
case 'bigint':
|
||||
return 'integer';
|
||||
case 'decimal':
|
||||
// 设置为 decimal,并设置对应精度
|
||||
return 'decimal:2';
|
||||
case 'float':
|
||||
case 'double':
|
||||
case 'real':
|
||||
return 'float';
|
||||
case 'bool':
|
||||
case 'boolean':
|
||||
return 'boolean';
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected function formatPropertyType(string $type, ?string $cast): ?string
|
||||
{
|
||||
if (! isset($cast)) {
|
||||
$cast = $this->formatDatabaseType($type) ?? 'string';
|
||||
}
|
||||
|
||||
switch ($cast) {
|
||||
case 'integer':
|
||||
return 'int';
|
||||
case 'date':
|
||||
case 'datetime':
|
||||
return '\Carbon\Carbon';
|
||||
case 'json':
|
||||
return 'array';
|
||||
}
|
||||
|
||||
if (Str::startsWith($cast, 'decimal')) {
|
||||
// 如果 cast 为 decimal,则 @property 改为 string
|
||||
return 'string';
|
||||
}
|
||||
|
||||
return $cast;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
重新执行 `gen:model` 后,对应模型如下:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace App\Model;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property int $count
|
||||
* @property string $float_num
|
||||
* @property string $str
|
||||
* @property string $json
|
||||
* @property \Carbon\Carbon $created_at
|
||||
* @property \Carbon\Carbon $updated_at
|
||||
*/
|
||||
class UserExt extends Model
|
||||
{
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'user_ext';
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = ['id', 'count', 'float_num', 'str', 'json', 'created_at', 'updated_at'];
|
||||
/**
|
||||
* The attributes that should be cast to native types.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = ['id' => 'integer', 'count' => 'integer', 'float_num' => 'decimal:2', 'created_at' => 'datetime', 'updated_at' => 'datetime'];
|
||||
}
|
||||
```
|
||||
|
@ -25,15 +25,16 @@ composer require hyperf/database
|
||||
默认配置如下,数据库支持多库配置,默认为 `default`。
|
||||
|
||||
| 配置项 | 类型 | 默认值 | 备注 |
|
||||
|:--------------------:|:------:|:---------------:|:------------------:|
|
||||
| :------------------: | :----: | :-------------: | :----------------: |
|
||||
| driver | string | 无 | 数据库引擎 |
|
||||
| host | string | 无 | 数据库地址 |
|
||||
| database | string | 无 | 数据库默认 DB |
|
||||
| database | string | 无 | 数据库默认 DB |
|
||||
| username | string | 无 | 数据库用户名 |
|
||||
| password | string | null | 数据库密码 |
|
||||
| charset | string | utf8 | 数据库编码 |
|
||||
| collation | string | utf8_unicode_ci | 数据库编码 |
|
||||
| prefix | string | '' | 数据库模型前缀 |
|
||||
| timezone | string | null | 数据库时区 |
|
||||
| pool.min_connections | int | 1 | 连接池内最少连接数 |
|
||||
| pool.max_connections | int | 10 | 连接池内最大连接数 |
|
||||
| pool.connect_timeout | float | 10.0 | 连接等待超时时间 |
|
||||
@ -339,3 +340,24 @@ try{
|
||||
Db::rollBack();
|
||||
}
|
||||
```
|
||||
|
||||
## 输出刚刚执行的 SQL
|
||||
|
||||
> 当前方法仅能用于开发环境,线上部署前一定要去掉,不然会引起严重的内存泄露和数据混淆。
|
||||
|
||||
线上记录 `SQL`,请使用 [事件监听](/zh-cn/db/event)
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use Hyperf\DbConnection\Db;
|
||||
use App\Model\Book;
|
||||
|
||||
// 启用 SQL 数据记录功能
|
||||
Db::enableQueryLog();
|
||||
|
||||
$book = Book::query()->find(1);
|
||||
|
||||
// 打印最后一条 SQL 相关数据
|
||||
var_dump(Arr::last(Db::getQueryLog()));
|
||||
```
|
||||
|
@ -21,6 +21,8 @@ composer require hyperf/event
|
||||
|
||||
## 使用事件管理器
|
||||
|
||||
> 接下来我们会通过配置和注解两种方式介绍监听器,实际使用时,二者只需使用其一即可,如果既有注解又有配置,则会造成监听器被多次触发。
|
||||
|
||||
### 定义一个事件
|
||||
|
||||
一个事件其实就是一个用于管理状态数据的普通类,触发时将应用数据传递到事件里,然后监听器对事件类进行操作,一个事件可被多个监听器监听。
|
||||
@ -181,4 +183,3 @@ class UserService
|
||||
> `1.1.6` 版本及更新的版本已优化此问题
|
||||
|
||||
在 `1.1.6` 版本之前,因为 `BootApplication` 是在 `Command` 初始化 和 `Server` 启动前触发,所以当前环境一定是非协程环境,一旦使用了协程 `API`,则会导致启动失败。
|
||||
|
||||
|
124
docs/zh-cn/jet.md
Normal file
124
docs/zh-cn/jet.md
Normal file
@ -0,0 +1,124 @@
|
||||
# Jet
|
||||
|
||||
Jet 是一个统一模型的 RPC 客户端,内置 JSONRPC 协议的适配,该组件可适用于所有的 PHP 环境,包括 PHP-FPM 和 Swoole 或 Hyperf。(在 Hyperf 环境下,目前仍建议直接使用 `hyperf/json-rpc` 组件来作为客户端使用)
|
||||
|
||||
> 未来还会内置 gRPC 和 Tars 协议。
|
||||
|
||||
# 安装
|
||||
|
||||
```bash
|
||||
composer require hyperf/jet
|
||||
```
|
||||
|
||||
# 快速开始
|
||||
|
||||
## 注册协议
|
||||
|
||||
> 注册协议不是必须的一个步骤,但您可以通过 ProtocolManager 管理所有的协议。
|
||||
|
||||
您可以通过 `Hyperf\Jet\ProtocolManager` 类来注册管理任意的协议,每个协议会包含 Transporter, Packer, DataFormatter and PathGenerator 几个基本的组件,您可以注册一个 JSONRPC 协议,如下:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use Hyperf\Jet\DataFormatter\DataFormatter;
|
||||
use Hyperf\Jet\Packer\JsonEofPacker;
|
||||
use Hyperf\Jet\PathGenerator\PathGenerator;
|
||||
use Hyperf\Jet\ProtocolManager;
|
||||
use Hyperf\Jet\Transporter\StreamSocketTransporter;
|
||||
|
||||
ProtocolManager::register($protocol = 'jsonrpc', [
|
||||
ProtocolManager::TRANSPORTER => new StreamSocketTransporter(),
|
||||
ProtocolManager::PACKER => new JsonEofPacker(),
|
||||
ProtocolManager::PATH_GENERATOR => new PathGenerator(),
|
||||
ProtocolManager::DATA_FORMATTER => new DataFormatter(),
|
||||
]);
|
||||
```
|
||||
|
||||
## 注册服务
|
||||
|
||||
> 注册服务不是必须的一个步骤,但您可以通过 ServiceManager 管理所有的服务。
|
||||
|
||||
在您往 `Hyperf\Jet\ProtocolManager` 注册了一个协议之后,您可以通过 `Hyperf\Jet\ServiceManager` 将协议绑定到任意的服务上,如下:
|
||||
|
||||
```php
|
||||
<?php
|
||||
use Hyperf\Jet\ServiceManager;
|
||||
|
||||
// 绑定 CalculatorService 与 jsonrpc 协议,同时设定静态的节点信息
|
||||
ServiceManager::register($service = 'CalculatorService', $protocol = 'jsonrpc', [
|
||||
ServiceManager::NODES => [
|
||||
[$host = '127.0.0.1', $port = 9503],
|
||||
],
|
||||
]);
|
||||
```
|
||||
|
||||
## 调用 RPC 方法
|
||||
|
||||
### 通过 ClientFactory 调用
|
||||
|
||||
在您注册完协议与服务之后,您可以通过 `Hyperf/Jet/ClientFactory` 来获得您的服务的客户端,如下所示:
|
||||
|
||||
```php
|
||||
<?php
|
||||
use Hyperf\Jet\ClientFactory;
|
||||
|
||||
$clientFactory = new ClientFactory();
|
||||
$client = $clientFactory->create($service = 'CalculatorService', $protocol = 'jsonrpc');
|
||||
```
|
||||
|
||||
当您拥有 client 对象后,您可以通过该对象调用任意的远程方法,如下:
|
||||
|
||||
```php
|
||||
// 调用远程方法 `add` 并带上参数 `1` 和 `2`
|
||||
// $result 即为远程方法的返回值
|
||||
$result = $client->add(1, 2);
|
||||
```
|
||||
|
||||
当您调用一个不存在的远程方法时,客户端会抛出一个 `Hyperf\Jet\Exception\ServerException` 异常。
|
||||
|
||||
### 通过自定义客户端调用
|
||||
|
||||
您可以创建一个 `Hyperf\Jet\AbstractClient` 的子类作为自定义的客户端类,来完成远程方法的调用,比如,您希望定义一个 `CalculatorService` 服务的 `jsonrpc` 协议的客户端类,您可以先定义一个 `CalculatorService` 类,如下所示:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use Hyperf\Jet\AbstractClient;
|
||||
use Hyperf\Jet\Packer\JsonEofPacker;
|
||||
use Hyperf\Jet\Transporter\StreamSocketTransporter;
|
||||
use Hyperf\Rpc\Contract\DataFormatterInterface;
|
||||
use Hyperf\Rpc\Contract\PackerInterface;
|
||||
use Hyperf\Rpc\Contract\PathGeneratorInterface;
|
||||
use Hyperf\Rpc\Contract\TransporterInterface;
|
||||
|
||||
/**
|
||||
* @method int add(int $a, int $b);
|
||||
*/
|
||||
class CalculatorService extends AbstractClient
|
||||
{
|
||||
// 定义 `CalculatorService` 作为 $service 参数的默认值
|
||||
public function __construct(
|
||||
string $service = 'CalculatorService',
|
||||
TransporterInterface $transporter = null,
|
||||
PackerInterface $packer = null,
|
||||
?DataFormatterInterface $dataFormatter = null,
|
||||
?PathGeneratorInterface $pathGenerator = null
|
||||
) {
|
||||
// 这里指定 transporter,您仍然可以通过 ProtocolManager 来获得 transporter 或从构造函数传递
|
||||
$transporter = new StreamSocketTransporter('127.0.0.1', 9503);
|
||||
// 这里指定 packer,您仍然可以通过 ProtocolManager 来获得 packer 或从构造函数传递
|
||||
$packer = new JsonEofPacker();
|
||||
parent::__construct($service, $transporter, $packer, $dataFormatter, $pathGenerator);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
现在,您可以通过该类来直接调用远程方法了,如下所示:
|
||||
|
||||
```php
|
||||
// 调用远程方法 `add` 并带上参数 `1` 和 `2`
|
||||
// $result 即为远程方法的返回值
|
||||
$client = new CalculatorService();
|
||||
$result = $client->add(1, 2);
|
||||
```
|
@ -71,19 +71,31 @@ return [
|
||||
### 获取当前实例
|
||||
|
||||
```php
|
||||
$instance = new \Hyperf\Nacos\Instance();
|
||||
use Hyperf\Utils\ApplicationContext;
|
||||
use Hyperf\Nacos\Instance;
|
||||
|
||||
$container = ApplicationContext::getContainer();
|
||||
$instance = $container->get(Instance::class);
|
||||
```
|
||||
|
||||
### 获取当前服务
|
||||
|
||||
```php
|
||||
$service = new \Hyperf\Nacos\Service();
|
||||
use Hyperf\Utils\ApplicationContext;
|
||||
use Hyperf\Nacos\Service;
|
||||
|
||||
$container = ApplicationContext::getContainer();
|
||||
$service = $container->get(Service::class);
|
||||
```
|
||||
|
||||
### 获取一个服务的最优节点
|
||||
|
||||
```php
|
||||
$instance = make(NacosInstance::class);
|
||||
use Hyperf\Utils\ApplicationContext;
|
||||
use Hyperf\Nacos\Instance;
|
||||
|
||||
$container = ApplicationContext::getContainer();
|
||||
$instance = $container->get(Instance::class);
|
||||
|
||||
$service = new ServiceModel([
|
||||
'service_name' => 'hyperf',
|
||||
|
@ -251,6 +251,30 @@ class NsqCommand extends HyperfCommand
|
||||
}
|
||||
```
|
||||
|
||||
### NSQD HTTP API
|
||||
|
||||
> NSQD HTTP API Refer: https://nsq.io/components/nsqd.html
|
||||
|
||||
组件对 NSQD HTTP API 进行了封装,您可以很方便的实现对 NSQD HTTP API 的调用。
|
||||
|
||||
比如,当您需要删除某个 `Topic` 时,可以执行以下代码:
|
||||
|
||||
```php
|
||||
<?php
|
||||
use Hyperf\Utils\ApplicationContext;
|
||||
use Hyperf\Nsq\Nsqd\Topic;
|
||||
|
||||
$container = ApplicationContext::getContainer();
|
||||
|
||||
$client = $container->get(Topic::class);
|
||||
|
||||
$client->delete('hyperf.test');
|
||||
```
|
||||
|
||||
- `Hyperf\Nsq\Api\Topic` 类对应 `topic` 相关的 API;
|
||||
- `Hyperf\Nsq\Api\Channle` 类对应 `channel` 相关的 API;
|
||||
- `Hyperf\Nsq\Api\Api` 类对应 `ping`、`stats`、`config`、`debug` 等相关的 API;
|
||||
|
||||
## NSQ 协议
|
||||
|
||||
> https://nsq.io/clients/tcp_protocol_spec.html
|
||||
@ -319,7 +343,7 @@ client->server: AUTH
|
||||
|
||||
== pub ==
|
||||
note left of client: 发送一条消息
|
||||
client -> server: PUB <topic_name>
|
||||
client -> server: PUB~~~~ <topic_name>
|
||||
note left of client: 发送多条消息
|
||||
client -> server: MPUB
|
||||
note left of client: 发送一条延时消息
|
||||
@ -328,7 +352,7 @@ client -> server: DPUB
|
||||
|
||||
== sub ==
|
||||
note left of client: client 使用 channel 订阅 topic
|
||||
note right of server: SUB 成功后, client 出于 RDY 0 阶段
|
||||
note right of server: SUB 成功后, client 处于 RDY 0 阶段
|
||||
client -> server: SUB <topic_name> <channel_name>
|
||||
note left of client: 使用 RDY 告诉 server 准备好消费 <count> 条消息
|
||||
client -> server: RDY <count>
|
||||
|
@ -86,7 +86,7 @@ class FooProcess extends AbstractProcess
|
||||
// 您的代码 ...
|
||||
}
|
||||
|
||||
public function isEnable(): bool
|
||||
public function isEnable($server): bool
|
||||
{
|
||||
// 不跟随服务启动一同启动
|
||||
return false;
|
||||
|
@ -107,7 +107,7 @@ php -d swoole.use_shortname=Off bin/hyperf.php start
|
||||
|
||||
## 使用 AMQP 组件报 `Swoole\Error: API must be called in the coroutine` 错误
|
||||
|
||||
可以在 `config/autoload/amqp.php` 配置文件中将 `close_on_destruct` 改为 `false` 即可。
|
||||
可以在 `config/autoload/amqp.php` 配置文件中将 `params.close_on_destruct` 改为 `false` 即可。
|
||||
|
||||
## 使用 Swoole 4.5 版本和 view 组件时访问接口出现 404
|
||||
|
||||
@ -128,3 +128,13 @@ composer dump-autoload -o
|
||||
> 当环境变量存在 SCAN_CACHEABLE 时,.env 中无法修改这个配置。
|
||||
|
||||
`2.0.0` 和 `2.0.1` 两个版本,判断文件是否修改时,没有判断修改时间相等的情况,所以文件修改后,立马生成缓存的情况(比如使用 `watcher` 组件时), 会导致代码无法及时生效。
|
||||
|
||||
## 语法错误导致服务无法启动
|
||||
|
||||
当项目启动时,抛出类似于以下错误时
|
||||
|
||||
```
|
||||
Fatal error: Uncaught PhpParser\Error: Syntax error, unexpected T_STRING on line 27 in vendor/nikic/php-parser/lib/PhpParser/ParserAbstract.php:315
|
||||
```
|
||||
|
||||
可以执行脚本 `composer analyse`,对项目进行静态检测,便可以找到出现问题的代码段。
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
## 替换 `Handler`
|
||||
|
||||
以下以小程序为例,
|
||||
以下以公众号为例,
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -17,27 +17,27 @@ use EasyWeChat\Kernel\ServiceContainer;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\HandlerStack;
|
||||
use Hyperf\Guzzle\CoroutineHandler;
|
||||
use Hyperf\Guzzle\HandlerStackFactory;
|
||||
use Overtrue\Socialite\Providers\AbstractProvider;
|
||||
use Symfony\Component\HttpFoundation\ParameterBag;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
|
||||
$container = ApplicationContext::getContainer();
|
||||
|
||||
$app = Factory::miniProgram($config);
|
||||
$app = Factory::officialAccount($config);
|
||||
$handler = new CoroutineHandler();
|
||||
|
||||
// 设置 HttpClient,当前设置没有实际效果,在数据请求时会被 guzzle_handler 覆盖,但不保证 EasyWeChat 后面会修改这里。
|
||||
// 设置 HttpClient,部分接口直接使用了 http_client。
|
||||
$config = $app['config']->get('http', []);
|
||||
$config['handler'] = $container->get(HandlerStackFactory::class)->create();
|
||||
$config['handler'] = $stack = HandlerStack::create($handler);
|
||||
$app->rebind('http_client', new Client($config));
|
||||
|
||||
// 重写 Handler
|
||||
$app['guzzle_handler'] = new CoroutineHandler();
|
||||
// 部分接口在请求数据时,会根据 guzzle_handler 重置 Handler
|
||||
$app['guzzle_handler'] = $handler;
|
||||
|
||||
// 设置 OAuth 授权的 Guzzle 配置
|
||||
AbstractProvider::setGuzzleOptions([
|
||||
// 如果使用的是 OfficialAccount,则还需要设置以下参数
|
||||
$app->oauth->setGuzzleOptions([
|
||||
'http_errors' => false,
|
||||
'handler' => HandlerStack::create(new CoroutineHandler()),
|
||||
'handler' => $stack,
|
||||
]);
|
||||
```
|
||||
|
||||
@ -65,6 +65,7 @@ $xml = $this->request->getBody()->getContents();
|
||||
|
||||
```php
|
||||
<?php
|
||||
use Symfony\Component\HttpFoundation\HeaderBag;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
$get = $this->request->getQueryParams();
|
||||
@ -78,8 +79,9 @@ $files = [];
|
||||
foreach ($uploadFiles as $k => $v) {
|
||||
$files[$k] = $v->toArray();
|
||||
}
|
||||
$app['request'] = new Request($get, $post, [], $cookie, $files, $server, $xml);
|
||||
|
||||
$request = new Request($get, $post, [], $cookie, $files, $server, $xml);
|
||||
$request->headers = new HeaderBag($this->request->getHeaders());
|
||||
$app->rebind('request', $request);
|
||||
// Do something...
|
||||
|
||||
```
|
||||
|
@ -52,6 +52,8 @@ class TermSignalHandler implements SignalHandlerInterface
|
||||
|
||||
因为 Worker 进程接收的 SIGTERM 信号被捕获后,无法正常退出,所以用户可以直接 `Ctrl + C` 退出,或者修改 `config/autoload/signal.php` 配置,如下:
|
||||
|
||||
> WorkerStopHandler 不适配于 CoroutineServer,如有需要请自行实现
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
@ -66,3 +68,63 @@ return [
|
||||
```
|
||||
|
||||
`WorkerStopHandler` 触发后,会在所设置的 [max_wait_time](https://wiki.swoole.com/#/server/setting?id=max_wait_time) 配置时间后,关闭掉当前进程。
|
||||
|
||||
## 协程风格服务监听器配置示例
|
||||
|
||||
> 以上默认的监听器都是适配于异步风格服务的,如果需要在协程风格服务下使用,可以按照以下自定义配置
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Kernel\Signal;
|
||||
|
||||
use Hyperf\AsyncQueue\Driver\Driver;
|
||||
use Hyperf\Contract\ConfigInterface;
|
||||
use Hyperf\Process\ProcessManager;
|
||||
use Hyperf\Server\ServerManager;
|
||||
use Hyperf\Signal\SignalHandlerInterface;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
class CoroutineServerStopHandler implements SignalHandlerInterface
|
||||
{
|
||||
/**
|
||||
* @var ContainerInterface
|
||||
*/
|
||||
protected $container;
|
||||
|
||||
/**
|
||||
* @var ConfigInterface
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
public function __construct(ContainerInterface $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
$this->config = $container->get(ConfigInterface::class);
|
||||
}
|
||||
|
||||
public function listen(): array
|
||||
{
|
||||
// 协程风格只会存在一个 Worker 进程,故这里只需要监听 WORKER 即可
|
||||
return [
|
||||
[self::WORKER, SIGTERM],
|
||||
[self::WORKER, SIGINT],
|
||||
];
|
||||
}
|
||||
|
||||
public function handle(int $signal): void
|
||||
{
|
||||
// 异步队列会使用以下参数循环 pop 消息,v2.1以后版本会使用 ProcessManager::isRunning() 管理。
|
||||
Driver::$running = false;
|
||||
ProcessManager::setRunning(false);
|
||||
|
||||
foreach (ServerManager::list() as [$type, $server]) {
|
||||
// 循环关闭开启的服务
|
||||
$server->shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
@ -24,7 +24,6 @@ hyperf/socketio-server 组件是基于 WebSocket 实现的,请确保服务端
|
||||
],
|
||||
```
|
||||
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 服务端
|
||||
@ -338,6 +337,62 @@ class WebSocketController extends BaseNamespace
|
||||
}
|
||||
```
|
||||
|
||||
### 修改 `SocketIO` 基础参数
|
||||
|
||||
框架默认参数:
|
||||
|
||||
| 配置 | 类型 | 默认值 |
|
||||
| :--------------------: | :---: | :----: |
|
||||
| $pingTimeout | int | 100 |
|
||||
| $pingInterval | int | 10000 |
|
||||
| $clientCallbackTimeout | int | 10000 |
|
||||
|
||||
有时候,由于推送消息比较多或者网络较卡,在 100ms 内,无法及时返回 `PONG`,就会导致连接断开。这时候我们可以通过以下方式,进行重写:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Kernel;
|
||||
|
||||
use Hyperf\Contract\StdoutLoggerInterface;
|
||||
use Hyperf\SocketIOServer\Parser\Decoder;
|
||||
use Hyperf\SocketIOServer\Parser\Encoder;
|
||||
use Hyperf\SocketIOServer\SidProvider\SidProviderInterface;
|
||||
use Hyperf\SocketIOServer\SocketIO;
|
||||
use Hyperf\WebSocketServer\Sender;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
class SocketIOFactory
|
||||
{
|
||||
public function __invoke(ContainerInterface $container)
|
||||
{
|
||||
$io = new SocketIO(
|
||||
$container->get(StdoutLoggerInterface::class),
|
||||
$container->get(Sender::class),
|
||||
$container->get(Decoder::class),
|
||||
$container->get(Encoder::class),
|
||||
$container->get(SidProviderInterface::class)
|
||||
);
|
||||
|
||||
// 重写 pingTimeout 参数
|
||||
$io->setPingTimeout(10000);
|
||||
|
||||
return $io;
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
然后在 `dependencies.php` 添加对应映射即可。
|
||||
|
||||
```php
|
||||
return [
|
||||
Hyperf\SocketIOServer\SocketIO::class => App\Kernel\SocketIOFactory::class,
|
||||
];
|
||||
```
|
||||
|
||||
## Auth 鉴权
|
||||
|
||||
您可以通过使用中间件来拦截 WebSocket 握手,实现鉴权功能,如下:
|
||||
|
@ -17,6 +17,7 @@
|
||||
* [快速开始](zh-cn/quick-start/overview.md)
|
||||
* [常见问题](zh-cn/quick-start/questions.md)
|
||||
* [编程须知](zh-cn/quick-start/important.md)
|
||||
* [视频教程](https://course.swoole-cloud.com/videos/5/new?from=hyperf.io)
|
||||
|
||||
* 核心架构
|
||||
|
||||
@ -58,8 +59,8 @@
|
||||
* [模型事件](zh-cn/db/event.md)
|
||||
* [模型缓存](zh-cn/db/model-cache.md)
|
||||
* [数据库迁移](zh-cn/db/migration.md)
|
||||
* [极简 DB 组件](zh-cn/db/db.md)
|
||||
* [修改器](zh-cn/db/mutators.md)
|
||||
* [极简 DB 组件](zh-cn/db/db.md)
|
||||
|
||||
* 微服务
|
||||
|
||||
@ -67,14 +68,20 @@
|
||||
* [JSON RPC 服务](zh-cn/json-rpc.md)
|
||||
* [gRPC 服务](zh-cn/grpc.md)
|
||||
* [服务注册](zh-cn/service-register.md)
|
||||
* [服务重试](zh-cn/retry.md)
|
||||
* [服务熔断及降级](zh-cn/circuit-breaker.md)
|
||||
* [服务限流](zh-cn/rate-limit.md)
|
||||
* [配置中心](zh-cn/config-center.md)
|
||||
* [调用链追踪](zh-cn/tracer.md)
|
||||
* [服务监控](zh-cn/metric.md)
|
||||
* [服务重试](zh-cn/retry.md)
|
||||
* [Nacos](zh-cn/nacos.md)
|
||||
* [Snowflake](zh-cn/snowflake.md)
|
||||
|
||||
* 网络服务
|
||||
|
||||
* [TCP 服务](zh-cn/tcp-server.md)
|
||||
* [WebSocket 服务](zh-cn/websocket-server.md)
|
||||
* [Socket.io 服务](zh-cn/socketio-server.md)
|
||||
|
||||
* 消息队列
|
||||
|
||||
* [Redis 异步队列](zh-cn/async-queue.md)
|
||||
@ -82,31 +89,30 @@
|
||||
* [Nats](zh-cn/nats.md)
|
||||
* [NSQ](zh-cn/nsq.md)
|
||||
|
||||
* 其它组件
|
||||
* 客户端
|
||||
|
||||
* [连接池](zh-cn/pool.md)
|
||||
* [Redis 协程客户端](zh-cn/redis.md)
|
||||
* [Guzzle HTTP 协程客户端](zh-cn/guzzle.md)
|
||||
* [Elasticsearch 协程客户端](zh-cn/elasticsearch.md)
|
||||
* [Consul 协程客户端](zh-cn/consul.md)
|
||||
* [ETCD 协程客户端](zh-cn/etcd.md)
|
||||
* [WebSocket 服务](zh-cn/websocket-server.md)
|
||||
* [TCP 服务](zh-cn/tcp-server.md)
|
||||
* [WebSocket 协程客户端](zh-cn/websocket-client.md)
|
||||
* [Socket.io 服务](zh-cn/socketio-server.md)
|
||||
* [Nacos](zh-cn/nacos.md)
|
||||
* [Jet](zh-cn/jet.md)
|
||||
|
||||
* 其它组件
|
||||
|
||||
* [连接池](zh-cn/pool.md)
|
||||
* [自定义进程](zh-cn/process.md)
|
||||
* [开发者工具](zh-cn/devtool.md)
|
||||
* [辅助类](zh-cn/utils.md)
|
||||
* [限流器](zh-cn/rate-limit.md)
|
||||
* [Swoole Tracker](zh-cn/swoole-tracker.md)
|
||||
* [定时任务](zh-cn/crontab.md)
|
||||
* [Task 机制](zh-cn/task.md)
|
||||
* [枚举类](zh-cn/constants.md)
|
||||
* [Snowflake](zh-cn/snowflake.md)
|
||||
* [重试](zh-cn/retry.md)
|
||||
* [信号处理器](zh-cn/signal.md)
|
||||
* [ReactiveX](zh-cn/reactive-x.md)
|
||||
* [Watcher](zh-cn/watcher.md)
|
||||
* [开发者工具](zh-cn/devtool.md)
|
||||
* [Swoole Tracker](zh-cn/swoole-tracker.md)
|
||||
|
||||
* 应用部署
|
||||
|
||||
|
@ -32,18 +32,16 @@ Swoole Tracker 能够帮助企业自动分析并汇总统计关键系统调用
|
||||
|
||||
### 安装扩展
|
||||
|
||||
注册完账户后,进入[控制台](https://www.swoole-cloud.com/dashboard/catdemo/),并申请试用,下载对应客户端。
|
||||
注册完账户后,进入[控制台](https://business.swoole.com/SwooleTracker/catdemo),并申请试用,下载对应的安装脚本。
|
||||
|
||||
相关文档,请移步 [试用文档](https://www.kancloud.cn/swoole-inc/ee-base-wiki/1214079) 或 [详细文档](https://www.kancloud.cn/swoole-inc/ee-help-wiki/1213080)
|
||||
|
||||
> 具体文档地址,以从控制台下载的对应客户端中展示的为准。
|
||||
|
||||
将客户端中的所有文件以及以下两个文件复制到项目目录 `.build` 中
|
||||
将脚本以及以下两个文件复制到项目目录 `.build` 中
|
||||
|
||||
1. `entrypoint.sh`
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
#!/usr/bin/env sh
|
||||
|
||||
/opt/swoole/script/php/swoole_php /opt/swoole/node-agent/src/node.php &
|
||||
|
||||
@ -51,11 +49,11 @@ php /opt/www/bin/hyperf.php start
|
||||
|
||||
```
|
||||
|
||||
2. `swoole-tracker.ini`
|
||||
2. `swoole_tracker.ini`
|
||||
|
||||
```bash
|
||||
[swoole_tracker]
|
||||
extension=/opt/swoole_tracker.so
|
||||
extension=/opt/.build/swoole_tracker.so
|
||||
apm.enable=1 #打开总开关
|
||||
apm.sampling_rate=100 #采样率 例如:100%
|
||||
|
||||
@ -66,8 +64,15 @@ apm.enable_memcheck=1 #开启内存泄漏检测 默认0 关闭状态
|
||||
然后将下面的 `Dockerfile` 复制到项目根目录中。
|
||||
|
||||
```dockerfile
|
||||
FROM hyperf/hyperf:7.2-alpine-cli
|
||||
LABEL maintainer="Hyperf Developers <group@hyperf.io>" version="1.0" license="MIT"
|
||||
# Default Dockerfile
|
||||
#
|
||||
# @link https://www.hyperf.io
|
||||
# @document https://hyperf.wiki
|
||||
# @contact group@hyperf.io
|
||||
# @license https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE
|
||||
|
||||
FROM hyperf/hyperf:7.4-alpine-v3.11-cli
|
||||
LABEL maintainer="Hyperf Developers <group@hyperf.io>" version="1.0" license="MIT" app.name="Hyperf"
|
||||
|
||||
##
|
||||
# ---------- env settings ----------
|
||||
@ -76,28 +81,29 @@ LABEL maintainer="Hyperf Developers <group@hyperf.io>" version="1.0" license="MI
|
||||
ARG timezone
|
||||
|
||||
ENV TIMEZONE=${timezone:-"Asia/Shanghai"} \
|
||||
COMPOSER_VERSION=1.8.6 \
|
||||
APP_ENV=prod
|
||||
APP_ENV=prod \
|
||||
SCAN_CACHEABLE=(true)
|
||||
|
||||
# update
|
||||
RUN set -ex \
|
||||
&& apk update \
|
||||
# install composer
|
||||
&& cd /tmp \
|
||||
&& wget https://github.com/composer/composer/releases/download/${COMPOSER_VERSION}/composer.phar \
|
||||
&& wget https://mirrors.aliyun.com/composer/composer.phar \
|
||||
&& chmod u+x composer.phar \
|
||||
&& mv composer.phar /usr/local/bin/composer \
|
||||
# show php version and extensions
|
||||
&& php -v \
|
||||
&& php -m \
|
||||
&& php --ri swoole \
|
||||
# ---------- some config ----------
|
||||
&& cd /etc/php7 \
|
||||
# - config PHP
|
||||
&& { \
|
||||
echo "upload_max_filesize=100M"; \
|
||||
echo "post_max_size=108M"; \
|
||||
echo "memory_limit=1024M"; \
|
||||
echo "upload_max_filesize=128M"; \
|
||||
echo "post_max_size=128M"; \
|
||||
echo "memory_limit=1G"; \
|
||||
echo "date.timezone=${TIMEZONE}"; \
|
||||
} | tee conf.d/99-overrides.ini \
|
||||
} | tee conf.d/99_overrides.ini \
|
||||
# - config timezone
|
||||
&& ln -sf /usr/share/zoneinfo/${TIMEZONE} /etc/localtime \
|
||||
&& echo "${TIMEZONE}" > /etc/timezone \
|
||||
@ -105,25 +111,29 @@ RUN set -ex \
|
||||
&& rm -rf /var/cache/apk/* /tmp/* /usr/share/man \
|
||||
&& echo -e "\033[42;37m Build Completed :).\033[0m\n"
|
||||
|
||||
COPY . /opt/www
|
||||
WORKDIR /opt/www/.build
|
||||
COPY .build /opt/.build
|
||||
WORKDIR /opt/.build
|
||||
|
||||
# 这里的地址,以客户端中显示的为准
|
||||
RUN ./deploy_env.sh www.swoole-cloud.com \
|
||||
RUN chmod +x swoole-tracker-install.sh \
|
||||
&& ./swoole-tracker-install.sh \
|
||||
&& chmod 755 entrypoint.sh \
|
||||
&& cp swoole_tracker72.so /opt/swoole_tracker.so \
|
||||
&& cp swoole-tracker.ini /etc/php7/conf.d/swoole-tracker.ini \
|
||||
&& cp swoole-tracker/swoole_tracker74.so /opt/.build/swoole_tracker.so \
|
||||
&& cp swoole_tracker.ini /etc/php7/conf.d/98_swoole_tracker.ini \
|
||||
&& php -m
|
||||
|
||||
WORKDIR /opt/www
|
||||
|
||||
RUN composer install --no-dev \
|
||||
&& composer dump-autoload -o \
|
||||
&& php /opt/www/bin/hyperf.php di:init-proxy
|
||||
# Composer Cache
|
||||
# COPY ./composer.* /opt/www/
|
||||
# RUN composer install --no-dev --no-scripts
|
||||
|
||||
COPY . /opt/www
|
||||
RUN composer install --no-dev -o && php bin/hyperf.php
|
||||
|
||||
EXPOSE 9501
|
||||
|
||||
ENTRYPOINT ["sh", ".build/entrypoint.sh"]
|
||||
ENTRYPOINT ["sh", "/opt/.build/entrypoint.sh"]
|
||||
|
||||
```
|
||||
|
||||
## 使用
|
||||
@ -157,3 +167,15 @@ return [
|
||||
],
|
||||
];
|
||||
```
|
||||
|
||||
若使用 `jsonrpc-http` 协议实现了 `RPC` 服务,则还需要在 `config/autoload/aspects.php` 配置以下 `Aspect`:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
return [
|
||||
Hyperf\SwooleTracker\Aspect\CoroutineHandlerAspect::class,
|
||||
];
|
||||
```
|
||||
|
||||
|
||||
|
@ -52,7 +52,7 @@ return [
|
||||
|
||||
发布 Translation 组件的文件:
|
||||
|
||||
```php
|
||||
```bash
|
||||
php bin/hyperf.php vendor:publish hyperf/translation
|
||||
```
|
||||
|
||||
@ -349,7 +349,6 @@ if ($errors->has('foo')) {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## 验证规则
|
||||
|
||||
下面是有效规则及其函数列表:
|
||||
|
@ -168,6 +168,10 @@ return [
|
||||
|
||||
首先,我們實現一個用於複製上下文的 `Coroutine` 類。其中 `create()` 方法,可以將父類的上下文複製到子類當中。
|
||||
|
||||
為了避免命名衝突,約定使用 `class_map` 做為文件夾名,後跟要替換的命名空間的文件夾及文件。
|
||||
|
||||
如: `class_map/Hyperf/Utils/Coroutine.php`
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
@ -241,7 +245,7 @@ class Coroutine
|
||||
|
||||
然後,我們實現一個跟 `Hyperf\Utils\Coroutine` 一模一樣的對象。其中 `create()` 方法替換成我們上述實現的方法。
|
||||
|
||||
`app/Kernel/ClassMap/Coroutine.php`
|
||||
`class_map/Hyperf/Utils/Coroutine.php`
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -340,7 +344,7 @@ return [
|
||||
],
|
||||
'class_map' => [
|
||||
// 需要映射的類名 => 類所在的文件地址
|
||||
Coroutine::class => BASE_PATH . '/app/Kernel/ClassMap/Coroutine.php',
|
||||
Coroutine::class => BASE_PATH . '/class_map/Hyperf/Utils/Coroutine.php',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
@ -100,7 +100,7 @@ class FooAspect extends AbstractAspect
|
||||
}
|
||||
```
|
||||
|
||||
> 2.0 版本已經可以支持切入 Trait,但要求 PHP 版本 >= 7.3。
|
||||
> 2.0.3 及以上版本已經可以支持切入 Trait,但要求 PHP 版本 >= 7.3。
|
||||
|
||||
## 代理類緩存
|
||||
|
||||
|
@ -422,7 +422,7 @@ use Hyperf\Process\Annotation\Process;
|
||||
/**
|
||||
* @Process()
|
||||
*/
|
||||
class ConsumerProcess extends ConsumerProcess
|
||||
class OtherConsumerProcess extends ConsumerProcess
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
@ -445,6 +445,8 @@ return $driver->push(new ExampleJob());
|
||||
|
||||
異步隊列在終止時,如果正在進行消費邏輯,可能會導致出現錯誤。框架提供了 `DriverStopHandler` ,可以讓異步隊列進程安全關閉。
|
||||
|
||||
> 當前信號處理器並不適配於 CoroutineServer,如有需要請自行實現
|
||||
|
||||
安裝信號處理器
|
||||
|
||||
```
|
||||
|
@ -3,6 +3,8 @@
|
||||
所有官方提供的組件庫均已進行協程化處理,可安全地在 Hyperf 內或其它協程框架內使用,基於 Hyperf 的開放性和可擴展性,社區可對此開發或適配各種各樣的組件,得益於此,Hyperf 將存在着無限的可能性。
|
||||
本頁將收錄各個適配了 Hyperf 的協程組件 和 已經經過驗證可安全地用於協程下的常用庫,以便您快速的從中選擇合適的組件完成您的需求。
|
||||
|
||||
> 組件順序以收錄時間排序
|
||||
|
||||
## 如何提交我的組件?
|
||||
|
||||
如果您開發的協程組件適配了 Hyperf,那麼您可以直接對 [hyperf/hyperf](https://github.com/hyperf/hyperf) 項目的 `master` 分支發起您的 `Pull Request`,也就是更改當前頁`(zh-cn/awesome-components.md)`。
|
||||
|
@ -118,7 +118,7 @@ use Hyperf\Cache\Annotation\Cacheable;
|
||||
class DemoService
|
||||
{
|
||||
/**
|
||||
* @Cacheable(prefix="cache", value="_#{id}", listener="DemoServiceDelete")
|
||||
* @Cacheable(prefix="cache", value="_#{id}", listener="user-update")
|
||||
*/
|
||||
public function getCache(int $id)
|
||||
{
|
||||
|
@ -1,8 +1,93 @@
|
||||
# 版本更新記錄
|
||||
|
||||
# v2.0.9 - 2020-08-31
|
||||
|
||||
## 新增
|
||||
|
||||
- [#2331](https://github.com/hyperf/hyperf/pull/2331) [hyperf/nacos](https://github.com/hyperf/nacos) 組件增加授權接口。
|
||||
- [#2331](https://github.com/hyperf/hyperf/pull/2331) [hyperf/nacos](https://github.com/hyperf/nacos) 組件增加 `nacos.enable` 配置,用於控制是否啟用 `Nacos` 服務。
|
||||
- [#2331](https://github.com/hyperf/hyperf/pull/2331) [hyperf/nacos](https://github.com/hyperf/nacos) 組件增加配置合併類型,默認使用全量覆蓋。
|
||||
- [#2377](https://github.com/hyperf/hyperf/pull/2377) 為 gRPC 客户端 的 request 增加 `ts` 請求頭,以兼容 Node.js gRPC server 等。
|
||||
- [#2384](https://github.com/hyperf/hyperf/pull/2384) 新增助手函數 `optional()`,以創建 `Hyperf\Utils\Optional` 對象或更方便 Optional 的使用。
|
||||
|
||||
## 修改
|
||||
|
||||
- [#2331](https://github.com/hyperf/hyperf/pull/2331) 修復 [hyperf/nacos](https://github.com/hyperf/nacos) 組件,服務或配置不存在時,會拋出異常的問題。
|
||||
- [#2356](https://github.com/hyperf/hyperf/pull/2356) [#2368](https://github.com/hyperf/hyperf/pull/2368) 修復 `pid_file` 被用户修改後,命令行 `server:start` 啟動失敗的問題。
|
||||
- [#2358](https://github.com/hyperf/hyperf/pull/2358) 修復驗證器規則 `digits` 不支持 `int` 類型的問題。
|
||||
|
||||
## 優化
|
||||
|
||||
- [#2359](https://github.com/hyperf/hyperf/pull/2359) 優化自定義進程,在協程風格服務下,可以更加友好的停止。
|
||||
- [#2363](https://github.com/hyperf/hyperf/pull/2363) 優化 [hyperf/di](https://github.com/hyperf/di) 組件,使其不需要依賴 [hyperf/config](https://github.com/hyperf/config) 組件。
|
||||
- [#2373](https://github.com/hyperf/hyperf/pull/2373) 優化 [hyperf/validation](https://github.com/hyperf/validation) 組件的異常捕獲器,使其返回 `Response` 時,自動添加 `content-type 頭。
|
||||
|
||||
|
||||
# v2.0.8 - 2020-08-24
|
||||
|
||||
## 新增
|
||||
|
||||
- [#2334](https://github.com/hyperf/hyperf/pull/2334) 新增更加友好的數組遞歸合併方法 `Arr::merge`。
|
||||
- [#2335](https://github.com/hyperf/hyperf/pull/2335) 新增 `Hyperf/Utils/Optional`,它可以接受任意參數,並允許訪問該對象上的屬性或調用其方法,即使給定的對象為 `null`,也不會引發錯誤。
|
||||
- [#2336](https://github.com/hyperf/hyperf/pull/2336) 新增 `RedisNsqAdapter`,它通過 `NSQ` 發佈消息,使用 `Redis` 記錄房間信息。
|
||||
|
||||
## 修復
|
||||
|
||||
- [#2338](https://github.com/hyperf/hyperf/pull/2338) 修復文件系統使用 `S3` 適配器時,文件是否存在的邏輯與預期不符的 BUG。
|
||||
- [#2340](https://github.com/hyperf/hyperf/pull/2340) 修復 `__FUNCTION__` 和 `__METHOD__` 魔術方法無法在被 `AOP` 重寫的方法里正常工作的 BUG。
|
||||
|
||||
## 優化
|
||||
|
||||
- [#2319](https://github.com/hyperf/hyperf/pull/2319) 優化 `ResolverDispatcher` ,使項目發生循環依賴時,可以提供更加友好的錯誤提示。
|
||||
|
||||
# v2.0.7 - 2020-08-17
|
||||
|
||||
## 新增
|
||||
|
||||
- [#2307](https://github.com/hyperf/hyperf/pull/2307) [#2312](https://github.com/hyperf/hyperf/pull/2312) [hyperf/nsq](https://github.com/hyperf/nsq) 組件,新增 `NSQD` 的 `HTTP` 客户端。
|
||||
|
||||
## 修復
|
||||
|
||||
- [#2275](https://github.com/hyperf/hyperf/pull/2275) 修復配置中心,拉取配置進程會出現阻塞的 BUG。
|
||||
- [#2276](https://github.com/hyperf/hyperf/pull/2276) 修復 `Apollo` 配置中心,當配置沒有變更時,會清除所有本地配置項的 BUG。
|
||||
- [#2280](https://github.com/hyperf/hyperf/pull/2280) 修復 `Interface` 的方法會被 `AOP` 重寫,導致啟動報錯的 BUG。
|
||||
- [#2281](https://github.com/hyperf/hyperf/pull/2281) 當使用 `Task` 組件,且沒有啟動協程時,`Signal` 組件會導致啟動報錯的 BUG。
|
||||
- [#2304](https://github.com/hyperf/hyperf/pull/2304) 修復當使用 `SocketIOServer` 的內存適配器,刪除 `sid` 時,會導致死循環的 BUG。
|
||||
- [#2309](https://github.com/hyperf/hyperf/pull/2309) 修復 `JsonRpcHttpTransporter` 無法設置自定義超時時間的 BUG。
|
||||
|
||||
# v2.0.6 - 2020-08-10
|
||||
|
||||
## 新增
|
||||
|
||||
- [#2125](https://github.com/hyperf/hyperf/pull/2125) 新增 [hyperf/jet](https://github.com/hyperf/jet) 組件。`Jet` 是一個統一模型的 RPC 客户端,內置 JSONRPC 協議的適配,該組件可適用於所有的 `PHP (>= 7.2)` 環境,包括 PHP-FPM 和 Swoole 或 Hyperf。
|
||||
|
||||
## 修復
|
||||
|
||||
- [#2236](https://github.com/hyperf/hyperf/pull/2236) 修復 `Nacos` 使用負載均衡器選擇節點失敗的 BUG。
|
||||
- [#2242](https://github.com/hyperf/hyperf/pull/2242) 修復 `watcher` 組件會重複收集多次註解的 BUG。
|
||||
|
||||
# v2.0.5 - 2020-08-03
|
||||
|
||||
## 新增
|
||||
|
||||
- [#2001](https://github.com/hyperf/hyperf/pull/2001) 新增參數 `$signature`,用於簡化命令行的初始化工作。
|
||||
- [#2204](https://github.com/hyperf/hyperf/pull/2204) 為方法 `parallel` 增加 `$concurrent` 參數,用於快速設置併發量。
|
||||
|
||||
## 修復
|
||||
|
||||
- [#2210](https://github.com/hyperf/hyperf/pull/2210) 修復 `WebSocket` 握手成功後,不會立馬觸發 `OnOpen` 事件的 BUG。
|
||||
- [#2214](https://github.com/hyperf/hyperf/pull/2214) 修復 `WebSocket` 主動關閉連接時,不會觸發 `OnClose` 事件的 BUG。
|
||||
- [#2218](https://github.com/hyperf/hyperf/pull/2218) 修復在 `協程 Server` 下,`Sender::disconnect` 報錯的 BUG。
|
||||
- [#2227](https://github.com/hyperf/hyperf/pull/2227) 修復在 `協程 Server` 下,建立 `keepalive` 連接後,上下文數據無法在請求結束後銷燬的 BUG。
|
||||
|
||||
## 優化
|
||||
|
||||
- [#2193](https://github.com/hyperf/hyperf/pull/2193) 優化 `Hyperf\Watcher\Driver\FindDriver`,使其掃描有變動的文件更加精確。
|
||||
- [#2232](https://github.com/hyperf/hyperf/pull/2232) 優化 `model-cache` 的預加載功能,使其支持 `In` 和 `InRaw`。
|
||||
|
||||
# v2.0.4 - 2020-07-27
|
||||
|
||||
## Added
|
||||
## 新增
|
||||
|
||||
- [#2144](https://github.com/hyperf/hyperf/pull/2144) 數據庫查詢事件 `Hyperf\Database\Events\QueryExecuted` 添加 `$result` 字段。
|
||||
- [#2158](https://github.com/hyperf/hyperf/pull/2158) 路由 `Hyperf\HttpServer\Router\Handler` 中,添加 `$options` 字段。
|
||||
@ -12,12 +97,12 @@
|
||||
- [#2175](https://github.com/hyperf/hyperf/pull/2175) 模型生成器添加 `ModelRewriteSoftDeletesVisitor`,用於根據數據庫字段 `deleted_at`, 添加或者移除 `SoftDeletes`。
|
||||
- [#2176](https://github.com/hyperf/hyperf/pull/2176) 模型生成器添加 `ModelRewriteKeyInfoVisitor`,用於根據數據庫主鍵,重寫模型字段 `$incrementing` `$primaryKey` 和 `$keyType`。
|
||||
|
||||
## Fixed
|
||||
## 修復
|
||||
|
||||
- [#2149](https://github.com/hyperf/hyperf/pull/2149) 修復自定義進程運行過程中無法從 Nacos 正常更新配置的 BUG。
|
||||
- [#2159](https://github.com/hyperf/hyperf/pull/2159) 修復使用 `gen:migration` 時,由於文件已經存在導致的 `FATAL` 異常。
|
||||
|
||||
## Optimized
|
||||
## 優化
|
||||
|
||||
- [#2043](https://github.com/hyperf/hyperf/pull/2043) 當 `SCAN` 目錄都不存在時,拋出更加友好的異常。
|
||||
- [#2182](https://github.com/hyperf/hyperf/pull/2182) 當使用 `WebSocket` 和 `Http` 服務且 `Http` 接口被訪問時,不會記錄 `WebSocket` 關閉連接的日誌。
|
||||
|
@ -162,7 +162,6 @@ class FooCommand extends HyperfCommand
|
||||
|
||||
執行 `php bin/hyperf.php foo:hello Hyperf` 我們就能看到輸出了 `Hello Hyperf` 了。
|
||||
|
||||
|
||||
## 命令常用配置介紹
|
||||
|
||||
以下代碼皆只修改 `configure` 和 `handle` 中的內容。
|
||||
@ -360,6 +359,69 @@ array(2) {
|
||||
|
||||
```
|
||||
|
||||
## 通過 `$signature` 配置命令行
|
||||
|
||||
命令行除了上述配置方法外,還支持使用 `$signature` 配置。
|
||||
|
||||
> 需要 command 版本 >= 2.0.5
|
||||
|
||||
`$signature` 為字符串,分為三部分,分別是 `command` `argument` 和 `option`,如下:
|
||||
|
||||
```
|
||||
command:name {argument?* : The argument description.} {--option=* : The option description.}
|
||||
```
|
||||
|
||||
- `?` 代表 `非必傳`。
|
||||
- `*` 代表 `數組`。
|
||||
- `?*` 代表 `非必傳的數組`。
|
||||
- `=` 代表 `非 Bool`。
|
||||
|
||||
### 示例
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use Hyperf\Command\Annotation\Command;
|
||||
use Hyperf\Command\Command as HyperfCommand;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
/**
|
||||
* @Command
|
||||
*/
|
||||
class DebugCommand extends HyperfCommand
|
||||
{
|
||||
/**
|
||||
* @var ContainerInterface
|
||||
*/
|
||||
protected $container;
|
||||
|
||||
protected $signature = 'test:test {id : user_id} {--name= : user_name}';
|
||||
|
||||
public function __construct(ContainerInterface $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function configure()
|
||||
{
|
||||
parent::configure();
|
||||
$this->setDescription('Hyperf Demo Command');
|
||||
}
|
||||
|
||||
public function handle()
|
||||
{
|
||||
var_dump($this->input->getArguments());
|
||||
var_dump($this->input->getOptions());
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
# 運行命令
|
||||
|
||||
## 命令行中運行
|
||||
|
@ -2,17 +2,19 @@
|
||||
|
||||
我們提供了 `QQ 羣` 和 `微信羣` 兩種溝通途徑,非本頁面提供的其它交流途徑均非官方行為。
|
||||
|
||||
## QQ 羣
|
||||
## QQ 交流羣
|
||||
|
||||
Hyperf 交流羣(已滿): `862099724`
|
||||
Hyperf 交流 2 羣: `811414891`
|
||||
|
||||
## 微信羣
|
||||
## 微信交流羣
|
||||
|
||||
由於微信羣無法直接加入,故可先加下方二維碼好友,並聲明目的,再拉您入羣。
|
||||
|
||||
## Contributor 羣
|
||||
|
||||
為了更好的發展 Hyperf 的社區,我們專門為 Hyperf Contributor 提供了一個微信羣,以便我們對 Pull Request 或迭代計劃進行更詳細的探討,由於微信羣無法直接加入,故可先加下方二維碼好友,並聲明目的且帶上您已經被 Merged 的 Pull Request,再拉您入羣。
|
||||
|
||||
![wechat](imgs/wechat.jpg ':size=375')
|
||||
|
||||
## Community 釘釘羣
|
||||
|
||||
為了更好的發展 Hyperf 的開源社區,以及幫助您更容易參與進來,我們提供了 Hyperf Community 釘釘羣,以便社區對 Pull Request 或迭代計劃進行更詳細的探討,歡迎希望參與進 Hyperf 開源事業的您加入。
|
||||
|
||||
釘釘羣號:34538367
|
||||
|
@ -3,145 +3,47 @@
|
||||
`Hyperf` 官方提供了工具來快速創建組件包。
|
||||
|
||||
```
|
||||
# 創建適配 Hyperf 最新版本的組件包
|
||||
composer create-project hyperf/component-creater your_component dev-master
|
||||
|
||||
# 創建適配 Hyperf 1.1 版本的組件包
|
||||
composer create-project hyperf/component-creater your_component "1.1.*"
|
||||
```
|
||||
|
||||
執行結果如下:
|
||||
## 在項目中使用未發佈的組件包
|
||||
|
||||
假設項目目錄如下
|
||||
|
||||
```
|
||||
$ composer create-project hyperf/component-creater your_component dev-master
|
||||
Installing hyperf/component-creater (dev-master 2a626139a08be9cc3b23e9f03592ccf1b7d3158a)
|
||||
- Installing hyperf/component-creater (dev-master 2a62613): Cloning 2a626139a0 from cache
|
||||
Created project in your_component
|
||||
> Installer\Script::install
|
||||
Setting up optional packages
|
||||
What is your component name (hyperf/demo): sample/component
|
||||
What is your component license (MIT) : MIT
|
||||
What is your component description : Sample Component
|
||||
What is your namespace (Sample\Component): Sample\Component
|
||||
Removing installer development dependencies
|
||||
|
||||
Do you want to use hyperf/framework component ?
|
||||
[1] yes
|
||||
[n] None of the above
|
||||
Make your selection or type a composer package name and version (n): 1
|
||||
- Adding package hyperf/framework (1.0.*)
|
||||
|
||||
Do you want to use hyperf/di component ?
|
||||
[1] yes
|
||||
[n] None of the above
|
||||
Make your selection or type a composer package name and version (n): 1
|
||||
- Adding package hyperf/di (1.0.*)
|
||||
Remove installer
|
||||
Adding .gitattributes
|
||||
Removing Expressive installer classes, configuration, tests and docs
|
||||
Loading composer repositories with package information
|
||||
Updating dependencies (including require-dev)
|
||||
Package operations: 85 installs, 0 updates, 0 removals
|
||||
- Installing ocramius/package-versions (1.4.0): Loading from cache
|
||||
- Installing swoole/ide-helper (dev-master 9de6d57): Cloning 9de6d57310 from cache
|
||||
- Installing doctrine/inflector (v1.3.0): Loading from cache
|
||||
- Installing psr/log (1.1.0): Loading from cache
|
||||
- Installing psr/event-dispatcher (1.0.0): Loading from cache
|
||||
- Installing psr/container (1.0.0): Loading from cache
|
||||
- Installing hyperf/contract (v1.0.6): Loading from cache
|
||||
- Installing hyperf/utils (v1.0.6): Loading from cache
|
||||
- Installing psr/http-message (1.0.1): Loading from cache
|
||||
- Installing fig/http-message-util (1.1.3): Loading from cache
|
||||
- Installing hyperf/framework (v1.0.6): Loading from cache
|
||||
- Installing psr/http-server-handler (1.0.1): Loading from cache
|
||||
- Installing psr/http-server-middleware (1.0.1): Loading from cache
|
||||
- Installing hyperf/dispatcher (v1.0.6): Loading from cache
|
||||
- Installing hyperf/di (v1.0.6): Loading from cache
|
||||
- Installing hyperf/event (v1.0.5): Loading from cache
|
||||
- Installing doctrine/instantiator (1.2.0): Loading from cache
|
||||
- Installing php-di/phpdoc-reader (2.1.0): Loading from cache
|
||||
- Installing symfony/finder (v4.3.3): Loading from cache
|
||||
- Installing doctrine/lexer (1.0.2): Loading from cache
|
||||
- Installing doctrine/annotations (v1.6.1): Loading from cache
|
||||
- Installing nikic/php-parser (v4.2.2): Loading from cache
|
||||
- Installing symfony/service-contracts (v1.1.5): Loading from cache
|
||||
- Installing symfony/polyfill-php73 (v1.11.0): Loading from cache
|
||||
- Installing symfony/polyfill-mbstring (v1.11.0): Loading from cache
|
||||
- Installing symfony/console (v4.3.3): Loading from cache
|
||||
- Installing symfony/stopwatch (v4.3.3): Loading from cache
|
||||
- Installing symfony/process (v4.3.3): Loading from cache
|
||||
- Installing symfony/polyfill-php72 (v1.11.0): Loading from cache
|
||||
- Installing paragonie/random_compat (v9.99.99): Loading from cache
|
||||
- Installing symfony/polyfill-php70 (v1.11.0): Loading from cache
|
||||
- Installing symfony/options-resolver (v4.3.3): Loading from cache
|
||||
- Installing symfony/polyfill-ctype (v1.11.0): Loading from cache
|
||||
- Installing symfony/filesystem (v4.3.3): Loading from cache
|
||||
- Installing symfony/event-dispatcher-contracts (v1.1.5): Loading from cache
|
||||
- Installing symfony/event-dispatcher (v4.3.3): Loading from cache
|
||||
- Installing php-cs-fixer/diff (v1.3.0): Loading from cache
|
||||
- Installing composer/xdebug-handler (1.3.3): Loading from cache
|
||||
- Installing composer/semver (1.5.0): Loading from cache
|
||||
- Installing friendsofphp/php-cs-fixer (v2.15.1): Loading from cache
|
||||
- Installing hyperf/server (v1.0.6): Loading from cache
|
||||
- Installing zendframework/zend-stdlib (3.2.1): Loading from cache
|
||||
- Installing zendframework/zend-mime (2.7.1): Loading from cache
|
||||
- Installing hyperf/http-message (v1.0.6): Loading from cache
|
||||
- Installing hyperf/exception-handler (v1.0.1): Loading from cache
|
||||
- Installing nikic/fast-route (v1.3.0): Loading from cache
|
||||
- Installing hyperf/http-server (v1.0.6): Loading from cache
|
||||
- Installing sebastian/version (2.0.1): Loading from cache
|
||||
- Installing sebastian/resource-operations (2.0.1): Loading from cache
|
||||
- Installing sebastian/recursion-context (3.0.0): Loading from cache
|
||||
- Installing sebastian/object-reflector (1.1.1): Loading from cache
|
||||
- Installing sebastian/object-enumerator (3.0.3): Loading from cache
|
||||
- Installing sebastian/global-state (2.0.0): Loading from cache
|
||||
- Installing sebastian/exporter (3.1.0): Loading from cache
|
||||
- Installing sebastian/environment (4.2.2): Loading from cache
|
||||
- Installing sebastian/diff (3.0.2): Loading from cache
|
||||
- Installing sebastian/comparator (3.0.2): Loading from cache
|
||||
- Installing phpunit/php-timer (2.1.2): Loading from cache
|
||||
- Installing phpunit/php-text-template (1.2.1): Loading from cache
|
||||
- Installing phpunit/php-file-iterator (2.0.2): Loading from cache
|
||||
- Installing theseer/tokenizer (1.1.3): Loading from cache
|
||||
- Installing sebastian/code-unit-reverse-lookup (1.0.1): Loading from cache
|
||||
- Installing phpunit/php-token-stream (3.1.0): Loading from cache
|
||||
- Installing phpunit/php-code-coverage (6.1.4): Loading from cache
|
||||
- Installing webmozart/assert (1.4.0): Loading from cache
|
||||
- Installing phpdocumentor/reflection-common (1.0.1): Loading from cache
|
||||
- Installing phpdocumentor/type-resolver (0.4.0): Loading from cache
|
||||
- Installing phpdocumentor/reflection-docblock (4.3.1): Loading from cache
|
||||
- Installing phpspec/prophecy (1.8.1): Loading from cache
|
||||
- Installing phar-io/version (2.0.1): Loading from cache
|
||||
- Installing phar-io/manifest (1.0.3): Loading from cache
|
||||
- Installing myclabs/deep-copy (1.9.1): Loading from cache
|
||||
- Installing phpunit/phpunit (7.5.14): Loading from cache
|
||||
- Installing hyperf/testing (v1.0.2): Loading from cache
|
||||
- Installing phpstan/phpdoc-parser (0.3.5): Loading from cache
|
||||
- Installing nette/utils (v3.0.1): Loading from cache
|
||||
- Installing nette/finder (v2.5.0): Loading from cache
|
||||
- Installing nette/robot-loader (v3.2.0): Loading from cache
|
||||
- Installing nette/schema (v1.0.0): Loading from cache
|
||||
- Installing nette/php-generator (v3.2.3): Loading from cache
|
||||
- Installing nette/neon (v3.0.0): Loading from cache
|
||||
- Installing nette/di (v3.0.0): Loading from cache
|
||||
- Installing nette/bootstrap (v3.0.0): Loading from cache
|
||||
- Installing jean85/pretty-package-versions (1.2): Loading from cache
|
||||
- Installing phpstan/phpstan (0.10.8): Loading from cache
|
||||
hyperf/utils suggests installing symfony/var-dumper (Required to use the dd function (^4.1).)
|
||||
hyperf/framework suggests installing hyperf/command (Required to use Command annotation.)
|
||||
hyperf/di suggests installing hyperf/config (Require this component for annotation scan progress to retrieve the scan path.)
|
||||
symfony/service-contracts suggests installing symfony/service-implementation
|
||||
symfony/console suggests installing symfony/lock
|
||||
paragonie/random_compat suggests installing ext-libsodium (Provides a modern crypto API that can be used to generate random bytes.)
|
||||
symfony/event-dispatcher suggests installing symfony/dependency-injection
|
||||
symfony/event-dispatcher suggests installing symfony/http-kernel
|
||||
friendsofphp/php-cs-fixer suggests installing php-cs-fixer/phpunit-constraint-isidenticalstring (For IsIdenticalString constraint.)
|
||||
friendsofphp/php-cs-fixer suggests installing php-cs-fixer/phpunit-constraint-xmlmatchesxsd (For XmlMatchesXsd constraint.)
|
||||
zendframework/zend-mime suggests installing zendframework/zend-mail (Zend\Mail component)
|
||||
sebastian/global-state suggests installing ext-uopz (*)
|
||||
phpunit/php-code-coverage suggests installing ext-xdebug (^2.6.0)
|
||||
phpunit/phpunit suggests installing phpunit/php-invoker (^2.0)
|
||||
phpunit/phpunit suggests installing ext-xdebug (*)
|
||||
nette/bootstrap suggests installing tracy/tracy (to use Configurator::enableTracy())
|
||||
Writing lock file
|
||||
Generating autoload files
|
||||
ocramius/package-versions: Generating version class...
|
||||
ocramius/package-versions: ...done generating version class
|
||||
Do you want to remove the existing VCS (.git, .svn..) history? [Y,n]? Y
|
||||
/opt/project // 項目目錄
|
||||
/opt/your_component // 組件包目錄
|
||||
```
|
||||
|
||||
假設組件名為 `your_component/your_component`
|
||||
|
||||
修改 /opt/project/composer.json
|
||||
|
||||
> 以下省略其他不相干的配置
|
||||
|
||||
```json
|
||||
{
|
||||
"require": {
|
||||
"your_component/your_component": "dev-master"
|
||||
},
|
||||
"repositories": {
|
||||
"your_component": {
|
||||
"type": "path",
|
||||
"url": "/opt/your_component"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
最後在目錄 `/opt/project` 中執行 `composer update -o` 即可。
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -68,7 +68,7 @@ return [
|
||||
|
||||
如需要設置守護進程化,可在 `settings` 中增加 `'daemonize' => 1`,執行 `php bin/hyperf.php start`後,程序將轉入後台作為守護進程運行
|
||||
|
||||
單獨的 Server 配置需要添加在對應 `servers` 的 `settings` 當中,如 `jsonrpc` 協議的 TCP Server 配置啟用 EOF 自動分包,和設置 EOF 字符串
|
||||
單獨的 Server 配置需要添加在對應 `servers` 的 `settings` 當中,如 `jsonrpc` 協議的 TCP Server 配置啟用 EOF 自動分包和設置 EOF 字符串
|
||||
```php
|
||||
<?php
|
||||
|
||||
|
@ -217,11 +217,10 @@ $res = Db::table('user')->select('gender', Db::raw('COUNT(0) AS `count`'))->grou
|
||||
|
||||
### 強制索引
|
||||
|
||||
數據庫出現的慢查問題, 90% 以上是索引不對, 其中有部分查詢是因為數據庫服務器的 `查詢優化器` 沒有使用最佳索引, 這時候就需要使用強制強制索引:
|
||||
數據庫出現的慢查問題, 90% 以上是索引不對, 其中有部分查詢是因為數據庫服務器的 `查詢優化器` 沒有使用最佳索引, 這時候就需要使用強制索引:
|
||||
|
||||
```php
|
||||
Db::table(Db::raw(sprintf("{$table} FORCE INDEX({$index})");
|
||||
|
||||
Db::table(Db::raw("{$table} FORCE INDEX({$index})"));
|
||||
```
|
||||
|
||||
### 原生方法
|
||||
|
@ -339,3 +339,24 @@ try{
|
||||
Db::rollBack();
|
||||
}
|
||||
```
|
||||
|
||||
## 輸出剛剛執行的 SQL
|
||||
|
||||
> 當前方法僅能用於開發環境,線上部署前一定要去掉,不然會引起嚴重的內存泄露和數據混淆。
|
||||
|
||||
線上記錄 `SQL`,請使用 [事件監聽](/zh-cn/db/event?id=sql-執行監聽器)
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use Hyperf\DbConnection\Db;
|
||||
use App\Model\Book;
|
||||
|
||||
// 啟用 SQL 數據記錄功能
|
||||
Db::enableQueryLog();
|
||||
|
||||
$book = Book::query()->find(1);
|
||||
|
||||
// 打印最後一條 SQL 相關數據
|
||||
var_dump(Arr::last(Db::getQueryLog()));
|
||||
```
|
||||
|
@ -21,6 +21,8 @@ composer require hyperf/event
|
||||
|
||||
## 使用事件管理器
|
||||
|
||||
> 接下來我們會通過配置和註解兩種方式介紹監聽器,實際使用時,二者只需使用其一即可,如果既有註解又有配置,則會造成監聽器被多次觸發。
|
||||
|
||||
### 定義一個事件
|
||||
|
||||
一個事件其實就是一個用於管理狀態數據的普通類,觸發時將應用數據傳遞到事件裏,然後監聽器對事件類進行操作,一個事件可被多個監聽器監聽。
|
||||
@ -181,4 +183,3 @@ class UserService
|
||||
> `1.1.6` 版本及更新的版本已優化此問題
|
||||
|
||||
在 `1.1.6` 版本之前,因為 `BootApplication` 是在 `Command` 初始化 和 `Server` 啟動前觸發,所以當前環境一定是非協程環境,一旦使用了協程 `API`,則會導致啟動失敗。
|
||||
|
||||
|
@ -122,3 +122,67 @@ $client = make(Client::class, [
|
||||
],
|
||||
]);
|
||||
```
|
||||
|
||||
## 使用 `ClassMap` 替換 `GuzzleHttp\Client`
|
||||
|
||||
如果第三方組件並沒有提供可以替換 `Handler` 的接口,我們也可以通過 `ClassMap` 功能,直接替換 `Client` 來達到將客户端協程化的目的。
|
||||
|
||||
> 當然,也可以使用 SWOOLE_HOOK 達到相同的目的。
|
||||
|
||||
代碼示例如下:
|
||||
|
||||
class_map/GuzzleHttp/Client.php
|
||||
|
||||
```php
|
||||
<?php
|
||||
namespace GuzzleHttp;
|
||||
|
||||
use GuzzleHttp\Psr7;
|
||||
use Hyperf\Guzzle\CoroutineHandler;
|
||||
use Hyperf\Utils\Coroutine;
|
||||
|
||||
class Client implements ClientInterface
|
||||
{
|
||||
// 代碼省略其他不變的代碼
|
||||
|
||||
public function __construct(array $config = [])
|
||||
{
|
||||
$inCoroutine = Coroutine::inCoroutine();
|
||||
if (!isset($config['handler'])) {
|
||||
// 對應的 Handler 可以按需選擇 CoroutineHandler 或 PoolHandler
|
||||
$config['handler'] = HandlerStack::create($inCoroutine ? new CoroutineHandler() : null);
|
||||
} elseif ($inCoroutine && $config['handler'] instanceof HandlerStack) {
|
||||
$config['handler']->setHandler(new CoroutineHandler());
|
||||
} elseif (!is_callable($config['handler'])) {
|
||||
throw new \InvalidArgumentException('handler must be a callable');
|
||||
}
|
||||
|
||||
// Convert the base_uri to a UriInterface
|
||||
if (isset($config['base_uri'])) {
|
||||
$config['base_uri'] = Psr7\uri_for($config['base_uri']);
|
||||
}
|
||||
|
||||
$this->configureDefaults($config);
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
config/autoload/annotations.php
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
|
||||
return [
|
||||
'scan' => [
|
||||
// ...
|
||||
'class_map' => [
|
||||
Client::class => BASE_PATH . '/class_map/GuzzleHttp/Client.php',
|
||||
],
|
||||
],
|
||||
];
|
||||
```
|
||||
|
124
docs/zh-hk/jet.md
Normal file
124
docs/zh-hk/jet.md
Normal file
@ -0,0 +1,124 @@
|
||||
# Jet
|
||||
|
||||
Jet 是一個統一模型的 RPC 客户端,內置 JSONRPC 協議的適配,該組件可適用於所有的 PHP 環境,包括 PHP-FPM 和 Swoole 或 Hyperf。(在 Hyperf 環境下,目前仍建議直接使用 `hyperf/json-rpc` 組件來作為客户端使用)
|
||||
|
||||
> 未來還會內置 gRPC 和 Tars 協議。
|
||||
|
||||
# 安裝
|
||||
|
||||
```bash
|
||||
composer require hyperf/jet
|
||||
```
|
||||
|
||||
# 快速開始
|
||||
|
||||
## 註冊協議
|
||||
|
||||
> 註冊協議不是必須的一個步驟,但您可以通過 ProtocolManager 管理所有的協議。
|
||||
|
||||
您可以通過 `Hyperf\Jet\ProtocolManager` 類來註冊管理任意的協議,每個協議會包含 Transporter, Packer, DataFormatter and PathGenerator 幾個基本的組件,您可以註冊一個 JSONRPC 協議,如下:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use Hyperf\Jet\DataFormatter\DataFormatter;
|
||||
use Hyperf\Jet\Packer\JsonEofPacker;
|
||||
use Hyperf\Jet\PathGenerator\PathGenerator;
|
||||
use Hyperf\Jet\ProtocolManager;
|
||||
use Hyperf\Jet\Transporter\StreamSocketTransporter;
|
||||
|
||||
ProtocolManager::register($protocol = 'jsonrpc', [
|
||||
ProtocolManager::TRANSPORTER => new StreamSocketTransporter(),
|
||||
ProtocolManager::PACKER => new JsonEofPacker(),
|
||||
ProtocolManager::PATH_GENERATOR => new PathGenerator(),
|
||||
ProtocolManager::DATA_FORMATTER => new DataFormatter(),
|
||||
]);
|
||||
```
|
||||
|
||||
## 註冊服務
|
||||
|
||||
> 註冊服務不是必須的一個步驟,但您可以通過 ServiceManager 管理所有的服務。
|
||||
|
||||
在您往 `Hyperf\Jet\ProtocolManager` 註冊了一個協議之後,您可以通過 `Hyperf\Jet\ServiceManager` 將協議綁定到任意的服務上,如下:
|
||||
|
||||
```php
|
||||
<?php
|
||||
use Hyperf\Jet\ServiceManager;
|
||||
|
||||
// 綁定 CalculatorService 與 jsonrpc 協議,同時設定靜態的節點信息
|
||||
ServiceManager::register($service = 'CalculatorService', $protocol = 'jsonrpc', [
|
||||
ServiceManager::NODES => [
|
||||
[$host = '127.0.0.1', $port = 9503],
|
||||
],
|
||||
]);
|
||||
```
|
||||
|
||||
## 調用 RPC 方法
|
||||
|
||||
### 通過 ClientFactory 調用
|
||||
|
||||
在您註冊完協議與服務之後,您可以通過 `Hyperf/Jet/ClientFactory` 來獲得您的服務的客户端,如下所示:
|
||||
|
||||
```php
|
||||
<?php
|
||||
use Hyperf\Jet\ClientFactory;
|
||||
|
||||
$clientFactory = new ClientFactory();
|
||||
$client = $clientFactory->create($service = 'CalculatorService', $protocol = 'jsonrpc');
|
||||
```
|
||||
|
||||
當您擁有 client 對象後,您可以通過該對象調用任意的遠程方法,如下:
|
||||
|
||||
```php
|
||||
// 調用遠程方法 `add` 並帶上參數 `1` 和 `2`
|
||||
// $result 即為遠程方法的返回值
|
||||
$result = $client->add(1, 2);
|
||||
```
|
||||
|
||||
當您調用一個不存在的遠程方法時,客户端會拋出一個 `Hyperf\Jet\Exception\ServerException` 異常。
|
||||
|
||||
### 通過自定義客户端調用
|
||||
|
||||
您可以創建一個 `Hyperf\Jet\AbstractClient` 的子類作為自定義的客户端類,來完成遠程方法的調用,比如,您希望定義一個 `CalculatorService` 服務的 `jsonrpc` 協議的客户端類,您可以先定義一個 `CalculatorService` 類,如下所示:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use Hyperf\Jet\AbstractClient;
|
||||
use Hyperf\Jet\Packer\JsonEofPacker;
|
||||
use Hyperf\Jet\Transporter\StreamSocketTransporter;
|
||||
use Hyperf\Rpc\Contract\DataFormatterInterface;
|
||||
use Hyperf\Rpc\Contract\PackerInterface;
|
||||
use Hyperf\Rpc\Contract\PathGeneratorInterface;
|
||||
use Hyperf\Rpc\Contract\TransporterInterface;
|
||||
|
||||
/**
|
||||
* @method int add(int $a, int $b);
|
||||
*/
|
||||
class CalculatorService extends AbstractClient
|
||||
{
|
||||
// 定義 `CalculatorService` 作為 $service 參數的默認值
|
||||
public function __construct(
|
||||
string $service = 'CalculatorService',
|
||||
TransporterInterface $transporter = null,
|
||||
PackerInterface $packer = null,
|
||||
?DataFormatterInterface $dataFormatter = null,
|
||||
?PathGeneratorInterface $pathGenerator = null
|
||||
) {
|
||||
// 這裏指定 transporter,您仍然可以通過 ProtocolManager 來獲得 transporter 或從構造函數傳遞
|
||||
$transporter = new StreamSocketTransporter('127.0.0.1', 9503);
|
||||
// 這裏指定 packer,您仍然可以通過 ProtocolManager 來獲得 packer 或從構造函數傳遞
|
||||
$packer = new JsonEofPacker();
|
||||
parent::__construct($service, $transporter, $packer, $dataFormatter, $pathGenerator);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
現在,您可以通過該類來直接調用遠程方法了,如下所示:
|
||||
|
||||
```php
|
||||
// 調用遠程方法 `add` 並帶上參數 `1` 和 `2`
|
||||
// $result 即為遠程方法的返回值
|
||||
$client = new CalculatorService();
|
||||
$result = $client->add(1, 2);
|
||||
```
|
@ -71,19 +71,31 @@ return [
|
||||
### 獲取當前實例
|
||||
|
||||
```php
|
||||
$instance = new \Hyperf\Nacos\Instance();
|
||||
use Hyperf\Utils\ApplicationContext;
|
||||
use Hyperf\Nacos\Instance;
|
||||
|
||||
$container = ApplicationContext::getContainer();
|
||||
$instance = $container->get(Instance::class);
|
||||
```
|
||||
|
||||
### 獲取當前服務
|
||||
|
||||
```php
|
||||
$service = new \Hyperf\Nacos\Service();
|
||||
use Hyperf\Utils\ApplicationContext;
|
||||
use Hyperf\Nacos\Service;
|
||||
|
||||
$container = ApplicationContext::getContainer();
|
||||
$service = $container->get(Service::class);
|
||||
```
|
||||
|
||||
### 獲取一個服務的最優節點
|
||||
|
||||
```php
|
||||
$instance = make(NacosInstance::class);
|
||||
use Hyperf\Utils\ApplicationContext;
|
||||
use Hyperf\Nacos\Instance;
|
||||
|
||||
$container = ApplicationContext::getContainer();
|
||||
$instance = $container->get(Instance::class);
|
||||
|
||||
$service = new ServiceModel([
|
||||
'service_name' => 'hyperf',
|
||||
|
@ -251,6 +251,30 @@ class NsqCommand extends HyperfCommand
|
||||
}
|
||||
```
|
||||
|
||||
### NSQD HTTP API
|
||||
|
||||
> NSQD HTTP API Refer: https://nsq.io/components/nsqd.html
|
||||
|
||||
組件對 NSQD HTTP API 進行了封裝,您可以很方便的實現對 NSQD HTTP API 的調用。
|
||||
|
||||
比如,當您需要刪除某個 `Topic` 時,可以執行以下代碼:
|
||||
|
||||
```php
|
||||
<?php
|
||||
use Hyperf\Utils\ApplicationContext;
|
||||
use Hyperf\Nsq\Nsqd\Topic;
|
||||
|
||||
$container = ApplicationContext::getContainer();
|
||||
|
||||
$client = $container->get(Topic::class);
|
||||
|
||||
$client->delete('hyperf.test');
|
||||
```
|
||||
|
||||
- `Hyperf\Nsq\Api\Topic` 類對應 `topic` 相關的 API;
|
||||
- `Hyperf\Nsq\Api\Channle` 類對應 `channel` 相關的 API;
|
||||
- `Hyperf\Nsq\Api\Api` 類對應 `ping`、`stats`、`config`、`debug` 等相關的 API;
|
||||
|
||||
## NSQ 協議
|
||||
|
||||
> https://nsq.io/clients/tcp_protocol_spec.html
|
||||
@ -319,7 +343,7 @@ client->server: AUTH
|
||||
|
||||
== pub ==
|
||||
note left of client: 發送一條消息
|
||||
client -> server: PUB <topic_name>
|
||||
client -> server: PUB~~~~ <topic_name>
|
||||
note left of client: 發送多條消息
|
||||
client -> server: MPUB
|
||||
note left of client: 發送一條延時消息
|
||||
@ -328,7 +352,7 @@ client -> server: DPUB
|
||||
|
||||
== sub ==
|
||||
note left of client: client 使用 channel 訂閲 topic
|
||||
note right of server: SUB 成功後, client 出於 RDY 0 階段
|
||||
note right of server: SUB 成功後, client 處於 RDY 0 階段
|
||||
client -> server: SUB <topic_name> <channel_name>
|
||||
note left of client: 使用 RDY 告訴 server 準備好消費 <count> 條消息
|
||||
client -> server: RDY <count>
|
||||
|
@ -86,7 +86,7 @@ class FooProcess extends AbstractProcess
|
||||
// 您的代碼 ...
|
||||
}
|
||||
|
||||
public function isEnable(): bool
|
||||
public function isEnable($server): bool
|
||||
{
|
||||
// 不跟隨服務啟動一同啟動
|
||||
return false;
|
||||
|
@ -128,3 +128,13 @@ composer dump-autoload -o
|
||||
> 當環境變量存在 SCAN_CACHEABLE 時,.env 中無法修改這個配置。
|
||||
|
||||
`2.0.0` 和 `2.0.1` 兩個版本,判斷文件是否修改時,沒有判斷修改時間相等的情況,所以文件修改後,立馬生成緩存的情況(比如使用 `watcher` 組件時), 會導致代碼無法及時生效。
|
||||
|
||||
## 語法錯誤導致服務無法啟動
|
||||
|
||||
當項目啟動時,拋出類似於以下錯誤時
|
||||
|
||||
```
|
||||
Fatal error: Uncaught PhpParser\Error: Syntax error, unexpected T_STRING on line 27 in vendor/nikic/php-parser/lib/PhpParser/ParserAbstract.php:315
|
||||
```
|
||||
|
||||
可以執行腳本 `composer analyse`,對項目進行靜態檢測,便可以找到出現問題的代碼段。
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
## 替換 `Handler`
|
||||
|
||||
以下以小程序為例,
|
||||
以下以公眾號為例,
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -17,27 +17,27 @@ use EasyWeChat\Kernel\ServiceContainer;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\HandlerStack;
|
||||
use Hyperf\Guzzle\CoroutineHandler;
|
||||
use Hyperf\Guzzle\HandlerStackFactory;
|
||||
use Overtrue\Socialite\Providers\AbstractProvider;
|
||||
use Symfony\Component\HttpFoundation\ParameterBag;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
|
||||
$container = ApplicationContext::getContainer();
|
||||
|
||||
$app = Factory::miniProgram($config);
|
||||
$app = Factory::officialAccount($config);
|
||||
$handler = new CoroutineHandler();
|
||||
|
||||
// 設置 HttpClient,當前設置沒有實際效果,在數據請求時會被 guzzle_handler 覆蓋,但不保證 EasyWeChat 後面會修改這裏。
|
||||
// 設置 HttpClient,部分接口直接使用了 http_client。
|
||||
$config = $app['config']->get('http', []);
|
||||
$config['handler'] = $container->get(HandlerStackFactory::class)->create();
|
||||
$config['handler'] = $stack = HandlerStack::create($handler);
|
||||
$app->rebind('http_client', new Client($config));
|
||||
|
||||
// 重寫 Handler
|
||||
$app['guzzle_handler'] = new CoroutineHandler();
|
||||
// 部分接口在請求數據時,會根據 guzzle_handler 重置 Handler
|
||||
$app['guzzle_handler'] = $handler;
|
||||
|
||||
// 設置 OAuth 授權的 Guzzle 配置
|
||||
AbstractProvider::setGuzzleOptions([
|
||||
// 如果使用的是 OfficialAccount,則還需要設置以下參數
|
||||
$app->oauth->setGuzzleOptions([
|
||||
'http_errors' => false,
|
||||
'handler' => HandlerStack::create(new CoroutineHandler()),
|
||||
'handler' => $stack,
|
||||
]);
|
||||
```
|
||||
|
||||
@ -65,6 +65,7 @@ $xml = $this->request->getBody()->getContents();
|
||||
|
||||
```php
|
||||
<?php
|
||||
use Symfony\Component\HttpFoundation\HeaderBag;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
$get = $this->request->getQueryParams();
|
||||
@ -78,8 +79,9 @@ $files = [];
|
||||
foreach ($uploadFiles as $k => $v) {
|
||||
$files[$k] = $v->toArray();
|
||||
}
|
||||
$app['request'] = new Request($get, $post, [], $cookie, $files, $server, $xml);
|
||||
|
||||
$request = new Request($get, $post, [], $cookie, $files, $server, $xml);
|
||||
$request->headers = new HeaderBag($this->request->getHeaders());
|
||||
$app->rebind('request', $request);
|
||||
// Do something...
|
||||
|
||||
```
|
||||
|
@ -52,6 +52,8 @@ class TermSignalHandler implements SignalHandlerInterface
|
||||
|
||||
因為 Worker 進程接收的 SIGTERM 信號被捕獲後,無法正常退出,所以用户可以直接 `Ctrl + C` 退出,或者修改 `config/autoload/signal.php` 配置,如下:
|
||||
|
||||
> WorkerStopHandler 不適配於 CoroutineServer,如有需要請自行實現
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
@ -66,3 +68,63 @@ return [
|
||||
```
|
||||
|
||||
`WorkerStopHandler` 觸發後,會在所設置的 [max_wait_time](https://wiki.swoole.com/#/server/setting?id=max_wait_time) 配置時間後,關閉掉當前進程。
|
||||
|
||||
## 協程風格服務監聽器配置示例
|
||||
|
||||
> 以上默認的監聽器都是適配於異步風格服務的,如果需要在協程風格服務下使用,可以按照以下自定義配置
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Kernel\Signal;
|
||||
|
||||
use Hyperf\AsyncQueue\Driver\Driver;
|
||||
use Hyperf\Contract\ConfigInterface;
|
||||
use Hyperf\Process\ProcessManager;
|
||||
use Hyperf\Server\ServerManager;
|
||||
use Hyperf\Signal\SignalHandlerInterface;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
class CoroutineServerStopHandler implements SignalHandlerInterface
|
||||
{
|
||||
/**
|
||||
* @var ContainerInterface
|
||||
*/
|
||||
protected $container;
|
||||
|
||||
/**
|
||||
* @var ConfigInterface
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
public function __construct(ContainerInterface $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
$this->config = $container->get(ConfigInterface::class);
|
||||
}
|
||||
|
||||
public function listen(): array
|
||||
{
|
||||
// 協程風格只會存在一個 Worker 進程,故這裏只需要監聽 WORKER 即可
|
||||
return [
|
||||
[self::WORKER, SIGTERM],
|
||||
[self::WORKER, SIGINT],
|
||||
];
|
||||
}
|
||||
|
||||
public function handle(int $signal): void
|
||||
{
|
||||
// 異步隊列會使用以下參數循環 pop 消息,v2.1以後版本會使用 ProcessManager::isRunning() 管理。
|
||||
Driver::$running = false;
|
||||
ProcessManager::setRunning(false);
|
||||
|
||||
foreach (ServerManager::list() as [$type, $server]) {
|
||||
// 循環關閉開啟的服務
|
||||
$server->shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
@ -17,6 +17,7 @@
|
||||
* [快速開始](zh-hk/quick-start/overview.md)
|
||||
* [常見問題](zh-hk/quick-start/questions.md)
|
||||
* [編程須知](zh-hk/quick-start/important.md)
|
||||
* [視頻教程](https://course.swoole-cloud.com/videos/5/new?from=hyperf.io)
|
||||
|
||||
* 核心架構
|
||||
|
||||
@ -58,8 +59,8 @@
|
||||
* [模型事件](zh-hk/db/event.md)
|
||||
* [模型緩存](zh-hk/db/model-cache.md)
|
||||
* [數據庫遷移](zh-hk/db/migration.md)
|
||||
* [極簡 DB 組件](zh-hk/db/db.md)
|
||||
* [修改器](zh-hk/db/mutators.md)
|
||||
* [極簡 DB 組件](zh-hk/db/db.md)
|
||||
|
||||
* 微服務
|
||||
|
||||
@ -67,14 +68,20 @@
|
||||
* [JSON RPC 服務](zh-hk/json-rpc.md)
|
||||
* [gRPC 服務](zh-hk/grpc.md)
|
||||
* [服務註冊](zh-hk/service-register.md)
|
||||
* [服務重試](zh-hk/retry.md)
|
||||
* [服務熔斷及降級](zh-hk/circuit-breaker.md)
|
||||
* [服務限流](zh-hk/rate-limit.md)
|
||||
* [配置中心](zh-hk/config-center.md)
|
||||
* [調用鏈追蹤](zh-hk/tracer.md)
|
||||
* [服務監控](zh-hk/metric.md)
|
||||
* [服務重試](zh-hk/retry.md)
|
||||
* [Nacos](zh-hk/nacos.md)
|
||||
* [Snowflake](zh-hk/snowflake.md)
|
||||
|
||||
* 網絡服務
|
||||
|
||||
* [TCP 服務](zh-hk/tcp-server.md)
|
||||
* [WebSocket 服務](zh-hk/websocket-server.md)
|
||||
* [Socket.io 服務](zh-hk/socketio-server.md)
|
||||
|
||||
* 消息隊列
|
||||
|
||||
* [Redis 異步隊列](zh-hk/async-queue.md)
|
||||
@ -82,30 +89,30 @@
|
||||
* [Nats](zh-hk/nats.md)
|
||||
* [NSQ](zh-hk/nsq.md)
|
||||
|
||||
* 其它組件
|
||||
* 客户端
|
||||
|
||||
* [連接池](zh-hk/pool.md)
|
||||
* [Redis 協程客户端](zh-hk/redis.md)
|
||||
* [Guzzle HTTP 協程客户端](zh-hk/guzzle.md)
|
||||
* [Elasticsearch 協程客户端](zh-hk/elasticsearch.md)
|
||||
* [Consul 協程客户端](zh-hk/consul.md)
|
||||
* [ETCD 協程客户端](zh-hk/etcd.md)
|
||||
* [WebSocket 服務](zh-hk/websocket-server.md)
|
||||
* [WebSocket 協程客户端](zh-hk/websocket-client.md)
|
||||
* [Socket.io 服務](zh-hk/socketio-server.md)
|
||||
* [Nacos](zh-hk/nacos.md)
|
||||
* [Jet](zh-hk/jet.md)
|
||||
|
||||
* 其它組件
|
||||
|
||||
* [連接池](zh-hk/pool.md)
|
||||
* [自定義進程](zh-hk/process.md)
|
||||
* [開發者工具](zh-hk/devtool.md)
|
||||
* [輔助類](zh-hk/utils.md)
|
||||
* [限流器](zh-hk/rate-limit.md)
|
||||
* [Swoole Tracker](zh-hk/swoole-tracker.md)
|
||||
* [定時任務](zh-hk/crontab.md)
|
||||
* [Task 機制](zh-hk/task.md)
|
||||
* [枚舉類](zh-hk/constants.md)
|
||||
* [Snowflake](zh-hk/snowflake.md)
|
||||
* [重試](zh-hk/retry.md)
|
||||
* [信號處理器](zh-hk/signal.md)
|
||||
* [ReactiveX](zh-hk/reactive-x.md)
|
||||
* [Watcher](zh-hk/watcher.md)
|
||||
* [開發者工具](zh-hk/devtool.md)
|
||||
* [Swoole Tracker](zh-hk/swoole-tracker.md)
|
||||
|
||||
* 應用部署
|
||||
|
||||
|
@ -119,7 +119,7 @@ WORKDIR /opt/www
|
||||
|
||||
RUN composer install --no-dev \
|
||||
&& composer dump-autoload -o \
|
||||
&& php /opt/www/bin/hyperf.php di:init-proxy
|
||||
&& php /opt/www/bin/hyperf.php
|
||||
|
||||
EXPOSE 9501
|
||||
|
||||
|
78
docs/zh-hk/tcp-server.md
Normal file
78
docs/zh-hk/tcp-server.md
Normal file
@ -0,0 +1,78 @@
|
||||
# TCP 服務
|
||||
|
||||
框架默認提供創建 `TCP/UDP` 服務的能力。只需要進行簡易的配置,便可使用。
|
||||
|
||||
## 使用 TCP 服務
|
||||
|
||||
> UDP 服務請自行修改配置
|
||||
|
||||
### 創建 TcpServer 類
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use Hyperf\Contract\OnReceiveInterface;
|
||||
|
||||
class TcpServer implements OnReceiveInterface
|
||||
{
|
||||
public function onReceive($server, int $fd, int $fromId, string $data): void
|
||||
{
|
||||
$server->send($fd, 'recv:' . $data);
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### 創建對應配置
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Hyperf\Server\Server;
|
||||
use Hyperf\Server\SwooleEvent;
|
||||
|
||||
return [
|
||||
// 刪除其他不相關的配置項
|
||||
'servers' => [
|
||||
[
|
||||
'name' => 'tcp',
|
||||
'type' => Server::SERVER_BASE,
|
||||
'host' => '0.0.0.0',
|
||||
'port' => 9504,
|
||||
'sock_type' => SWOOLE_SOCK_TCP,
|
||||
'callbacks' => [
|
||||
SwooleEvent::ON_RECEIVE => [App\Controller\TcpServer::class, 'onReceive'],
|
||||
],
|
||||
'settings' => [
|
||||
// 按需配置
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
```
|
||||
|
||||
### 實現客户端
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
$client = new \Swoole\Client(SWOOLE_SOCK_TCP);
|
||||
$client->connect('127.0.0.1', 9504);
|
||||
$client->send('Hello World.');
|
||||
$ret = $client->recv(); // recv:Hello World.
|
||||
```
|
||||
|
||||
## 事件
|
||||
|
||||
| 事件 | 備註 |
|
||||
| :---------------------: | :--------------: |
|
||||
| SwooleEvent::ON_CONNECT | 監聽連接進入事件 |
|
||||
| SwooleEvent::ON_RECEIVE | 監聽數據接收事件 |
|
||||
| SwooleEvent::ON_CLOSE | 監聽連接關閉事件 |
|
@ -52,7 +52,7 @@ return [
|
||||
|
||||
發佈 Translation 組件的文件:
|
||||
|
||||
```php
|
||||
```bash
|
||||
php bin/hyperf.php vendor:publish hyperf/translation
|
||||
```
|
||||
|
||||
@ -349,7 +349,6 @@ if ($errors->has('foo')) {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## 驗證規則
|
||||
|
||||
下面是有效規則及其函數列表:
|
||||
|
@ -80,7 +80,7 @@ class WebSocketController implements OnMessageInterface, OnOpenInterface, OnClos
|
||||
}
|
||||
```
|
||||
|
||||
接下來啟動 Server,便能看到對應啟動了一個 WebSocket Server 並監聽於 9502 端口,此時您便可以通過各種 WebSocket Client 來進行連接和進行數據傳輸了。
|
||||
接下來啟動 Server,便能看到對應啟動了一個 WebSocket Server 並監聽於 9502 端口,此時您便可以通過各種 WebSocket Client 來進行連接和數據傳輸了。
|
||||
|
||||
```
|
||||
$ php bin/hyperf.php start
|
||||
@ -90,6 +90,34 @@ $ php bin/hyperf.php start
|
||||
[INFO] HTTP Server listening at 0.0.0.0:9501
|
||||
```
|
||||
|
||||
!> 當我們同時監聽了 HTTP Server 的 9501 端口和 WebSocket Server 的 9502 端口時, WebSocket Client 可以通過 9501 和 9502 兩個端口連接 WebSocket Server,即連接 `ws://0.0.0.0:9501` 和 `ws://0.0.0.0:9502` 都可以成功。
|
||||
|
||||
因為 Swoole\WebSocket\Server 繼承自 Swoole\Http\Server,可以使用 HTTP 觸發所有 WebSocket 的推送,瞭解詳情可查看 [Swoole 文檔](https://wiki.swoole.com/#/websocket_server?id=websocketserver) onRequest 回調部分。
|
||||
|
||||
如需關閉,可以修改 `config/autoload/server.php` 文件給 `http` 服務中增加 `open_websocket_protocol` 配置項。
|
||||
|
||||
```php
|
||||
<?php
|
||||
return [
|
||||
// 這裏省略了該文件的其它配置
|
||||
'servers' => [
|
||||
[
|
||||
'name' => 'http',
|
||||
'type' => Server::SERVER_HTTP,
|
||||
'host' => '0.0.0.0',
|
||||
'port' => 9501,
|
||||
'sock_type' => SWOOLE_SOCK_TCP,
|
||||
'callbacks' => [
|
||||
SwooleEvent::ON_REQUEST => [Hyperf\HttpServer\Server::class, 'onRequest'],
|
||||
],
|
||||
'settings' => [
|
||||
'open_websocket_protocol' => false,
|
||||
]
|
||||
],
|
||||
]
|
||||
];
|
||||
```
|
||||
|
||||
## 連接上下文
|
||||
|
||||
WebSocket 服務的 onOpen, onMessage, onClose 回調並不在同一個協程下觸發,因此不能直接使用協程上下文存儲狀態信息。WebSocket Server 組件提供了 **連接級** 的上下文,API 與協程上下文完全一樣。
|
||||
|
@ -168,6 +168,10 @@ return [
|
||||
|
||||
首先,我們實現一個用於複製上下文的 `Coroutine` 類。其中 `create()` 方法,可以將父類的上下文複製到子類當中。
|
||||
|
||||
為了避免命名衝突,約定使用 `class_map` 做為資料夾名,後跟要替換的名稱空間的資料夾及檔案。
|
||||
|
||||
如: `class_map/Hyperf/Utils/Coroutine.php`
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
@ -241,7 +245,7 @@ class Coroutine
|
||||
|
||||
然後,我們實現一個跟 `Hyperf\Utils\Coroutine` 一模一樣的物件。其中 `create()` 方法替換成我們上述實現的方法。
|
||||
|
||||
`app/Kernel/ClassMap/Coroutine.php`
|
||||
`class_map/Hyperf/Utils/Coroutine.php`
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -340,7 +344,7 @@ return [
|
||||
],
|
||||
'class_map' => [
|
||||
// 需要對映的類名 => 類所在的檔案地址
|
||||
Coroutine::class => BASE_PATH . '/app/Kernel/ClassMap/Coroutine.php',
|
||||
Coroutine::class => BASE_PATH . '/class_map/Hyperf/Utils/Coroutine.php',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
@ -100,7 +100,7 @@ class FooAspect extends AbstractAspect
|
||||
}
|
||||
```
|
||||
|
||||
> 2.0 版本已經可以支援切入 Trait,但要求 PHP 版本 >= 7.3。
|
||||
> 2.0.3 及以上版本已經可以支援切入 Trait,但要求 PHP 版本 >= 7.3。
|
||||
|
||||
## 代理類快取
|
||||
|
||||
|
@ -422,7 +422,7 @@ use Hyperf\Process\Annotation\Process;
|
||||
/**
|
||||
* @Process()
|
||||
*/
|
||||
class ConsumerProcess extends ConsumerProcess
|
||||
class OtherConsumerProcess extends ConsumerProcess
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
@ -445,6 +445,8 @@ return $driver->push(new ExampleJob());
|
||||
|
||||
非同步佇列在終止時,如果正在進行消費邏輯,可能會導致出現錯誤。框架提供了 `DriverStopHandler` ,可以讓非同步佇列程序安全關閉。
|
||||
|
||||
> 當前訊號處理器並不適配於 CoroutineServer,如有需要請自行實現
|
||||
|
||||
安裝訊號處理器
|
||||
|
||||
```
|
||||
|
@ -3,6 +3,8 @@
|
||||
所有官方提供的元件庫均已進行協程化處理,可安全地在 Hyperf 內或其它協程框架內使用,基於 Hyperf 的開放性和可擴充套件性,社群可對此開發或適配各種各樣的元件,得益於此,Hyperf 將存在著無限的可能性。
|
||||
本頁將收錄各個適配了 Hyperf 的協程元件 和 已經經過驗證可安全地用於協程下的常用庫,以便您快速的從中選擇合適的元件完成您的需求。
|
||||
|
||||
> 元件順序以收錄時間排序
|
||||
|
||||
## 如何提交我的元件?
|
||||
|
||||
如果您開發的協程元件適配了 Hyperf,那麼您可以直接對 [hyperf/hyperf](https://github.com/hyperf/hyperf) 專案的 `master` 分支發起您的 `Pull Request`,也就是更改當前頁`(zh-cn/awesome-components.md)`。
|
||||
|
@ -118,7 +118,7 @@ use Hyperf\Cache\Annotation\Cacheable;
|
||||
class DemoService
|
||||
{
|
||||
/**
|
||||
* @Cacheable(prefix="cache", value="_#{id}", listener="DemoServiceDelete")
|
||||
* @Cacheable(prefix="cache", value="_#{id}", listener="user-update")
|
||||
*/
|
||||
public function getCache(int $id)
|
||||
{
|
||||
|
@ -1,8 +1,93 @@
|
||||
# 版本更新記錄
|
||||
|
||||
# v2.0.9 - 2020-08-31
|
||||
|
||||
## 新增
|
||||
|
||||
- [#2331](https://github.com/hyperf/hyperf/pull/2331) [hyperf/nacos](https://github.com/hyperf/nacos) 元件增加授權介面。
|
||||
- [#2331](https://github.com/hyperf/hyperf/pull/2331) [hyperf/nacos](https://github.com/hyperf/nacos) 元件增加 `nacos.enable` 配置,用於控制是否啟用 `Nacos` 服務。
|
||||
- [#2331](https://github.com/hyperf/hyperf/pull/2331) [hyperf/nacos](https://github.com/hyperf/nacos) 元件增加配置合併型別,預設使用全量覆蓋。
|
||||
- [#2377](https://github.com/hyperf/hyperf/pull/2377) 為 gRPC 客戶端 的 request 增加 `ts` 請求頭,以相容 Node.js gRPC server 等。
|
||||
- [#2384](https://github.com/hyperf/hyperf/pull/2384) 新增助手函式 `optional()`,以建立 `Hyperf\Utils\Optional` 物件或更方便 Optional 的使用。
|
||||
|
||||
## 修改
|
||||
|
||||
- [#2331](https://github.com/hyperf/hyperf/pull/2331) 修復 [hyperf/nacos](https://github.com/hyperf/nacos) 元件,服務或配置不存在時,會丟擲異常的問題。
|
||||
- [#2356](https://github.com/hyperf/hyperf/pull/2356) [#2368](https://github.com/hyperf/hyperf/pull/2368) 修復 `pid_file` 被使用者修改後,命令列 `server:start` 啟動失敗的問題。
|
||||
- [#2358](https://github.com/hyperf/hyperf/pull/2358) 修復驗證器規則 `digits` 不支援 `int` 型別的問題。
|
||||
|
||||
## 優化
|
||||
|
||||
- [#2359](https://github.com/hyperf/hyperf/pull/2359) 優化自定義程序,在協程風格服務下,可以更加友好的停止。
|
||||
- [#2363](https://github.com/hyperf/hyperf/pull/2363) 優化 [hyperf/di](https://github.com/hyperf/di) 元件,使其不需要依賴 [hyperf/config](https://github.com/hyperf/config) 元件。
|
||||
- [#2373](https://github.com/hyperf/hyperf/pull/2373) 優化 [hyperf/validation](https://github.com/hyperf/validation) 元件的異常捕獲器,使其返回 `Response` 時,自動新增 `content-type 頭。
|
||||
|
||||
|
||||
# v2.0.8 - 2020-08-24
|
||||
|
||||
## 新增
|
||||
|
||||
- [#2334](https://github.com/hyperf/hyperf/pull/2334) 新增更加友好的陣列遞迴合併方法 `Arr::merge`。
|
||||
- [#2335](https://github.com/hyperf/hyperf/pull/2335) 新增 `Hyperf/Utils/Optional`,它可以接受任意引數,並允許訪問該物件上的屬性或呼叫其方法,即使給定的物件為 `null`,也不會引發錯誤。
|
||||
- [#2336](https://github.com/hyperf/hyperf/pull/2336) 新增 `RedisNsqAdapter`,它通過 `NSQ` 釋出訊息,使用 `Redis` 記錄房間資訊。
|
||||
|
||||
## 修復
|
||||
|
||||
- [#2338](https://github.com/hyperf/hyperf/pull/2338) 修復檔案系統使用 `S3` 介面卡時,檔案是否存在的邏輯與預期不符的 BUG。
|
||||
- [#2340](https://github.com/hyperf/hyperf/pull/2340) 修復 `__FUNCTION__` 和 `__METHOD__` 魔術方法無法在被 `AOP` 重寫的方法里正常工作的 BUG。
|
||||
|
||||
## 優化
|
||||
|
||||
- [#2319](https://github.com/hyperf/hyperf/pull/2319) 優化 `ResolverDispatcher` ,使專案發生迴圈依賴時,可以提供更加友好的錯誤提示。
|
||||
|
||||
# v2.0.7 - 2020-08-17
|
||||
|
||||
## 新增
|
||||
|
||||
- [#2307](https://github.com/hyperf/hyperf/pull/2307) [#2312](https://github.com/hyperf/hyperf/pull/2312) [hyperf/nsq](https://github.com/hyperf/nsq) 元件,新增 `NSQD` 的 `HTTP` 客戶端。
|
||||
|
||||
## 修復
|
||||
|
||||
- [#2275](https://github.com/hyperf/hyperf/pull/2275) 修復配置中心,拉取配置程序會出現阻塞的 BUG。
|
||||
- [#2276](https://github.com/hyperf/hyperf/pull/2276) 修復 `Apollo` 配置中心,當配置沒有變更時,會清除所有本地配置項的 BUG。
|
||||
- [#2280](https://github.com/hyperf/hyperf/pull/2280) 修復 `Interface` 的方法會被 `AOP` 重寫,導致啟動報錯的 BUG。
|
||||
- [#2281](https://github.com/hyperf/hyperf/pull/2281) 當使用 `Task` 元件,且沒有啟動協程時,`Signal` 元件會導致啟動報錯的 BUG。
|
||||
- [#2304](https://github.com/hyperf/hyperf/pull/2304) 修復當使用 `SocketIOServer` 的記憶體介面卡,刪除 `sid` 時,會導致死迴圈的 BUG。
|
||||
- [#2309](https://github.com/hyperf/hyperf/pull/2309) 修復 `JsonRpcHttpTransporter` 無法設定自定義超時時間的 BUG。
|
||||
|
||||
# v2.0.6 - 2020-08-10
|
||||
|
||||
## 新增
|
||||
|
||||
- [#2125](https://github.com/hyperf/hyperf/pull/2125) 新增 [hyperf/jet](https://github.com/hyperf/jet) 元件。`Jet` 是一個統一模型的 RPC 客戶端,內建 JSONRPC 協議的適配,該元件可適用於所有的 `PHP (>= 7.2)` 環境,包括 PHP-FPM 和 Swoole 或 Hyperf。
|
||||
|
||||
## 修復
|
||||
|
||||
- [#2236](https://github.com/hyperf/hyperf/pull/2236) 修復 `Nacos` 使用負載均衡器選擇節點失敗的 BUG。
|
||||
- [#2242](https://github.com/hyperf/hyperf/pull/2242) 修復 `watcher` 元件會重複收集多次註解的 BUG。
|
||||
|
||||
# v2.0.5 - 2020-08-03
|
||||
|
||||
## 新增
|
||||
|
||||
- [#2001](https://github.com/hyperf/hyperf/pull/2001) 新增引數 `$signature`,用於簡化命令列的初始化工作。
|
||||
- [#2204](https://github.com/hyperf/hyperf/pull/2204) 為方法 `parallel` 增加 `$concurrent` 引數,用於快速設定併發量。
|
||||
|
||||
## 修復
|
||||
|
||||
- [#2210](https://github.com/hyperf/hyperf/pull/2210) 修復 `WebSocket` 握手成功後,不會立馬觸發 `OnOpen` 事件的 BUG。
|
||||
- [#2214](https://github.com/hyperf/hyperf/pull/2214) 修復 `WebSocket` 主動關閉連線時,不會觸發 `OnClose` 事件的 BUG。
|
||||
- [#2218](https://github.com/hyperf/hyperf/pull/2218) 修復在 `協程 Server` 下,`Sender::disconnect` 報錯的 BUG。
|
||||
- [#2227](https://github.com/hyperf/hyperf/pull/2227) 修復在 `協程 Server` 下,建立 `keepalive` 連線後,上下文資料無法在請求結束後銷燬的 BUG。
|
||||
|
||||
## 優化
|
||||
|
||||
- [#2193](https://github.com/hyperf/hyperf/pull/2193) 優化 `Hyperf\Watcher\Driver\FindDriver`,使其掃描有變動的檔案更加精確。
|
||||
- [#2232](https://github.com/hyperf/hyperf/pull/2232) 優化 `model-cache` 的預載入功能,使其支援 `In` 和 `InRaw`。
|
||||
|
||||
# v2.0.4 - 2020-07-27
|
||||
|
||||
## Added
|
||||
## 新增
|
||||
|
||||
- [#2144](https://github.com/hyperf/hyperf/pull/2144) 資料庫查詢事件 `Hyperf\Database\Events\QueryExecuted` 新增 `$result` 欄位。
|
||||
- [#2158](https://github.com/hyperf/hyperf/pull/2158) 路由 `Hyperf\HttpServer\Router\Handler` 中,新增 `$options` 欄位。
|
||||
@ -12,12 +97,12 @@
|
||||
- [#2175](https://github.com/hyperf/hyperf/pull/2175) 模型生成器新增 `ModelRewriteSoftDeletesVisitor`,用於根據資料庫欄位 `deleted_at`, 新增或者移除 `SoftDeletes`。
|
||||
- [#2176](https://github.com/hyperf/hyperf/pull/2176) 模型生成器新增 `ModelRewriteKeyInfoVisitor`,用於根據資料庫主鍵,重寫模型欄位 `$incrementing` `$primaryKey` 和 `$keyType`。
|
||||
|
||||
## Fixed
|
||||
## 修復
|
||||
|
||||
- [#2149](https://github.com/hyperf/hyperf/pull/2149) 修復自定義程序執行過程中無法從 Nacos 正常更新配置的 BUG。
|
||||
- [#2159](https://github.com/hyperf/hyperf/pull/2159) 修復使用 `gen:migration` 時,由於檔案已經存在導致的 `FATAL` 異常。
|
||||
|
||||
## Optimized
|
||||
## 優化
|
||||
|
||||
- [#2043](https://github.com/hyperf/hyperf/pull/2043) 當 `SCAN` 目錄都不存在時,丟擲更加友好的異常。
|
||||
- [#2182](https://github.com/hyperf/hyperf/pull/2182) 當使用 `WebSocket` 和 `Http` 服務且 `Http` 介面被訪問時,不會記錄 `WebSocket` 關閉連線的日誌。
|
||||
|
@ -162,7 +162,6 @@ class FooCommand extends HyperfCommand
|
||||
|
||||
執行 `php bin/hyperf.php foo:hello Hyperf` 我們就能看到輸出了 `Hello Hyperf` 了。
|
||||
|
||||
|
||||
## 命令常用配置介紹
|
||||
|
||||
以下程式碼皆只修改 `configure` 和 `handle` 中的內容。
|
||||
@ -360,6 +359,69 @@ array(2) {
|
||||
|
||||
```
|
||||
|
||||
## 通過 `$signature` 配置命令列
|
||||
|
||||
命令列除了上述配置方法外,還支援使用 `$signature` 配置。
|
||||
|
||||
> 需要 command 版本 >= 2.0.5
|
||||
|
||||
`$signature` 為字串,分為三部分,分別是 `command` `argument` 和 `option`,如下:
|
||||
|
||||
```
|
||||
command:name {argument?* : The argument description.} {--option=* : The option description.}
|
||||
```
|
||||
|
||||
- `?` 代表 `非必傳`。
|
||||
- `*` 代表 `陣列`。
|
||||
- `?*` 代表 `非必傳的陣列`。
|
||||
- `=` 代表 `非 Bool`。
|
||||
|
||||
### 示例
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use Hyperf\Command\Annotation\Command;
|
||||
use Hyperf\Command\Command as HyperfCommand;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
/**
|
||||
* @Command
|
||||
*/
|
||||
class DebugCommand extends HyperfCommand
|
||||
{
|
||||
/**
|
||||
* @var ContainerInterface
|
||||
*/
|
||||
protected $container;
|
||||
|
||||
protected $signature = 'test:test {id : user_id} {--name= : user_name}';
|
||||
|
||||
public function __construct(ContainerInterface $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function configure()
|
||||
{
|
||||
parent::configure();
|
||||
$this->setDescription('Hyperf Demo Command');
|
||||
}
|
||||
|
||||
public function handle()
|
||||
{
|
||||
var_dump($this->input->getArguments());
|
||||
var_dump($this->input->getOptions());
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
# 執行命令
|
||||
|
||||
## 命令列中執行
|
||||
|
@ -2,17 +2,19 @@
|
||||
|
||||
我們提供了 `QQ 群` 和 `微信群` 兩種溝通途徑,非本頁面提供的其它交流途徑均非官方行為。
|
||||
|
||||
## QQ 群
|
||||
## QQ 交流群
|
||||
|
||||
Hyperf 交流群(已滿): `862099724`
|
||||
Hyperf 交流 2 群: `811414891`
|
||||
|
||||
## 微信群
|
||||
## 微信交流群
|
||||
|
||||
由於微信群無法直接加入,故可先加下方二維碼好友,並宣告目的,再拉您入群。
|
||||
|
||||
## Contributor 群
|
||||
|
||||
為了更好的發展 Hyperf 的社群,我們專門為 Hyperf Contributor 提供了一個微信群,以便我們對 Pull Request 或迭代計劃進行更詳細的探討,由於微信群無法直接加入,故可先加下方二維碼好友,並宣告目的且帶上您已經被 Merged 的 Pull Request,再拉您入群。
|
||||
|
||||
![wechat](imgs/wechat.jpg ':size=375')
|
||||
|
||||
## Community 釘釘群
|
||||
|
||||
為了更好的發展 Hyperf 的開源社群,以及幫助您更容易參與進來,我們提供了 Hyperf Community 釘釘群,以便社群對 Pull Request 或迭代計劃進行更詳細的探討,歡迎希望參與進 Hyperf 開源事業的您加入。
|
||||
|
||||
釘釘群號:34538367
|
||||
|
@ -3,145 +3,47 @@
|
||||
`Hyperf` 官方提供了工具來快速建立元件包。
|
||||
|
||||
```
|
||||
# 建立適配 Hyperf 最新版本的元件包
|
||||
composer create-project hyperf/component-creater your_component dev-master
|
||||
|
||||
# 建立適配 Hyperf 1.1 版本的元件包
|
||||
composer create-project hyperf/component-creater your_component "1.1.*"
|
||||
```
|
||||
|
||||
執行結果如下:
|
||||
## 在專案中使用未釋出的元件包
|
||||
|
||||
假設專案目錄如下
|
||||
|
||||
```
|
||||
$ composer create-project hyperf/component-creater your_component dev-master
|
||||
Installing hyperf/component-creater (dev-master 2a626139a08be9cc3b23e9f03592ccf1b7d3158a)
|
||||
- Installing hyperf/component-creater (dev-master 2a62613): Cloning 2a626139a0 from cache
|
||||
Created project in your_component
|
||||
> Installer\Script::install
|
||||
Setting up optional packages
|
||||
What is your component name (hyperf/demo): sample/component
|
||||
What is your component license (MIT) : MIT
|
||||
What is your component description : Sample Component
|
||||
What is your namespace (Sample\Component): Sample\Component
|
||||
Removing installer development dependencies
|
||||
|
||||
Do you want to use hyperf/framework component ?
|
||||
[1] yes
|
||||
[n] None of the above
|
||||
Make your selection or type a composer package name and version (n): 1
|
||||
- Adding package hyperf/framework (1.0.*)
|
||||
|
||||
Do you want to use hyperf/di component ?
|
||||
[1] yes
|
||||
[n] None of the above
|
||||
Make your selection or type a composer package name and version (n): 1
|
||||
- Adding package hyperf/di (1.0.*)
|
||||
Remove installer
|
||||
Adding .gitattributes
|
||||
Removing Expressive installer classes, configuration, tests and docs
|
||||
Loading composer repositories with package information
|
||||
Updating dependencies (including require-dev)
|
||||
Package operations: 85 installs, 0 updates, 0 removals
|
||||
- Installing ocramius/package-versions (1.4.0): Loading from cache
|
||||
- Installing swoole/ide-helper (dev-master 9de6d57): Cloning 9de6d57310 from cache
|
||||
- Installing doctrine/inflector (v1.3.0): Loading from cache
|
||||
- Installing psr/log (1.1.0): Loading from cache
|
||||
- Installing psr/event-dispatcher (1.0.0): Loading from cache
|
||||
- Installing psr/container (1.0.0): Loading from cache
|
||||
- Installing hyperf/contract (v1.0.6): Loading from cache
|
||||
- Installing hyperf/utils (v1.0.6): Loading from cache
|
||||
- Installing psr/http-message (1.0.1): Loading from cache
|
||||
- Installing fig/http-message-util (1.1.3): Loading from cache
|
||||
- Installing hyperf/framework (v1.0.6): Loading from cache
|
||||
- Installing psr/http-server-handler (1.0.1): Loading from cache
|
||||
- Installing psr/http-server-middleware (1.0.1): Loading from cache
|
||||
- Installing hyperf/dispatcher (v1.0.6): Loading from cache
|
||||
- Installing hyperf/di (v1.0.6): Loading from cache
|
||||
- Installing hyperf/event (v1.0.5): Loading from cache
|
||||
- Installing doctrine/instantiator (1.2.0): Loading from cache
|
||||
- Installing php-di/phpdoc-reader (2.1.0): Loading from cache
|
||||
- Installing symfony/finder (v4.3.3): Loading from cache
|
||||
- Installing doctrine/lexer (1.0.2): Loading from cache
|
||||
- Installing doctrine/annotations (v1.6.1): Loading from cache
|
||||
- Installing nikic/php-parser (v4.2.2): Loading from cache
|
||||
- Installing symfony/service-contracts (v1.1.5): Loading from cache
|
||||
- Installing symfony/polyfill-php73 (v1.11.0): Loading from cache
|
||||
- Installing symfony/polyfill-mbstring (v1.11.0): Loading from cache
|
||||
- Installing symfony/console (v4.3.3): Loading from cache
|
||||
- Installing symfony/stopwatch (v4.3.3): Loading from cache
|
||||
- Installing symfony/process (v4.3.3): Loading from cache
|
||||
- Installing symfony/polyfill-php72 (v1.11.0): Loading from cache
|
||||
- Installing paragonie/random_compat (v9.99.99): Loading from cache
|
||||
- Installing symfony/polyfill-php70 (v1.11.0): Loading from cache
|
||||
- Installing symfony/options-resolver (v4.3.3): Loading from cache
|
||||
- Installing symfony/polyfill-ctype (v1.11.0): Loading from cache
|
||||
- Installing symfony/filesystem (v4.3.3): Loading from cache
|
||||
- Installing symfony/event-dispatcher-contracts (v1.1.5): Loading from cache
|
||||
- Installing symfony/event-dispatcher (v4.3.3): Loading from cache
|
||||
- Installing php-cs-fixer/diff (v1.3.0): Loading from cache
|
||||
- Installing composer/xdebug-handler (1.3.3): Loading from cache
|
||||
- Installing composer/semver (1.5.0): Loading from cache
|
||||
- Installing friendsofphp/php-cs-fixer (v2.15.1): Loading from cache
|
||||
- Installing hyperf/server (v1.0.6): Loading from cache
|
||||
- Installing zendframework/zend-stdlib (3.2.1): Loading from cache
|
||||
- Installing zendframework/zend-mime (2.7.1): Loading from cache
|
||||
- Installing hyperf/http-message (v1.0.6): Loading from cache
|
||||
- Installing hyperf/exception-handler (v1.0.1): Loading from cache
|
||||
- Installing nikic/fast-route (v1.3.0): Loading from cache
|
||||
- Installing hyperf/http-server (v1.0.6): Loading from cache
|
||||
- Installing sebastian/version (2.0.1): Loading from cache
|
||||
- Installing sebastian/resource-operations (2.0.1): Loading from cache
|
||||
- Installing sebastian/recursion-context (3.0.0): Loading from cache
|
||||
- Installing sebastian/object-reflector (1.1.1): Loading from cache
|
||||
- Installing sebastian/object-enumerator (3.0.3): Loading from cache
|
||||
- Installing sebastian/global-state (2.0.0): Loading from cache
|
||||
- Installing sebastian/exporter (3.1.0): Loading from cache
|
||||
- Installing sebastian/environment (4.2.2): Loading from cache
|
||||
- Installing sebastian/diff (3.0.2): Loading from cache
|
||||
- Installing sebastian/comparator (3.0.2): Loading from cache
|
||||
- Installing phpunit/php-timer (2.1.2): Loading from cache
|
||||
- Installing phpunit/php-text-template (1.2.1): Loading from cache
|
||||
- Installing phpunit/php-file-iterator (2.0.2): Loading from cache
|
||||
- Installing theseer/tokenizer (1.1.3): Loading from cache
|
||||
- Installing sebastian/code-unit-reverse-lookup (1.0.1): Loading from cache
|
||||
- Installing phpunit/php-token-stream (3.1.0): Loading from cache
|
||||
- Installing phpunit/php-code-coverage (6.1.4): Loading from cache
|
||||
- Installing webmozart/assert (1.4.0): Loading from cache
|
||||
- Installing phpdocumentor/reflection-common (1.0.1): Loading from cache
|
||||
- Installing phpdocumentor/type-resolver (0.4.0): Loading from cache
|
||||
- Installing phpdocumentor/reflection-docblock (4.3.1): Loading from cache
|
||||
- Installing phpspec/prophecy (1.8.1): Loading from cache
|
||||
- Installing phar-io/version (2.0.1): Loading from cache
|
||||
- Installing phar-io/manifest (1.0.3): Loading from cache
|
||||
- Installing myclabs/deep-copy (1.9.1): Loading from cache
|
||||
- Installing phpunit/phpunit (7.5.14): Loading from cache
|
||||
- Installing hyperf/testing (v1.0.2): Loading from cache
|
||||
- Installing phpstan/phpdoc-parser (0.3.5): Loading from cache
|
||||
- Installing nette/utils (v3.0.1): Loading from cache
|
||||
- Installing nette/finder (v2.5.0): Loading from cache
|
||||
- Installing nette/robot-loader (v3.2.0): Loading from cache
|
||||
- Installing nette/schema (v1.0.0): Loading from cache
|
||||
- Installing nette/php-generator (v3.2.3): Loading from cache
|
||||
- Installing nette/neon (v3.0.0): Loading from cache
|
||||
- Installing nette/di (v3.0.0): Loading from cache
|
||||
- Installing nette/bootstrap (v3.0.0): Loading from cache
|
||||
- Installing jean85/pretty-package-versions (1.2): Loading from cache
|
||||
- Installing phpstan/phpstan (0.10.8): Loading from cache
|
||||
hyperf/utils suggests installing symfony/var-dumper (Required to use the dd function (^4.1).)
|
||||
hyperf/framework suggests installing hyperf/command (Required to use Command annotation.)
|
||||
hyperf/di suggests installing hyperf/config (Require this component for annotation scan progress to retrieve the scan path.)
|
||||
symfony/service-contracts suggests installing symfony/service-implementation
|
||||
symfony/console suggests installing symfony/lock
|
||||
paragonie/random_compat suggests installing ext-libsodium (Provides a modern crypto API that can be used to generate random bytes.)
|
||||
symfony/event-dispatcher suggests installing symfony/dependency-injection
|
||||
symfony/event-dispatcher suggests installing symfony/http-kernel
|
||||
friendsofphp/php-cs-fixer suggests installing php-cs-fixer/phpunit-constraint-isidenticalstring (For IsIdenticalString constraint.)
|
||||
friendsofphp/php-cs-fixer suggests installing php-cs-fixer/phpunit-constraint-xmlmatchesxsd (For XmlMatchesXsd constraint.)
|
||||
zendframework/zend-mime suggests installing zendframework/zend-mail (Zend\Mail component)
|
||||
sebastian/global-state suggests installing ext-uopz (*)
|
||||
phpunit/php-code-coverage suggests installing ext-xdebug (^2.6.0)
|
||||
phpunit/phpunit suggests installing phpunit/php-invoker (^2.0)
|
||||
phpunit/phpunit suggests installing ext-xdebug (*)
|
||||
nette/bootstrap suggests installing tracy/tracy (to use Configurator::enableTracy())
|
||||
Writing lock file
|
||||
Generating autoload files
|
||||
ocramius/package-versions: Generating version class...
|
||||
ocramius/package-versions: ...done generating version class
|
||||
Do you want to remove the existing VCS (.git, .svn..) history? [Y,n]? Y
|
||||
/opt/project // 專案目錄
|
||||
/opt/your_component // 元件包目錄
|
||||
```
|
||||
|
||||
假設元件名為 `your_component/your_component`
|
||||
|
||||
修改 /opt/project/composer.json
|
||||
|
||||
> 以下省略其他不相干的配置
|
||||
|
||||
```json
|
||||
{
|
||||
"require": {
|
||||
"your_component/your_component": "dev-master"
|
||||
},
|
||||
"repositories": {
|
||||
"your_component": {
|
||||
"type": "path",
|
||||
"url": "/opt/your_component"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
最後在目錄 `/opt/project` 中執行 `composer update -o` 即可。
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -68,7 +68,7 @@ return [
|
||||
|
||||
如需要設定守護程序化,可在 `settings` 中增加 `'daemonize' => 1`,執行 `php bin/hyperf.php start`後,程式將轉入後臺作為守護程序執行
|
||||
|
||||
單獨的 Server 配置需要新增在對應 `servers` 的 `settings` 當中,如 `jsonrpc` 協議的 TCP Server 配置啟用 EOF 自動分包,和設定 EOF 字串
|
||||
單獨的 Server 配置需要新增在對應 `servers` 的 `settings` 當中,如 `jsonrpc` 協議的 TCP Server 配置啟用 EOF 自動分包和設定 EOF 字串
|
||||
```php
|
||||
<?php
|
||||
|
||||
|
@ -217,11 +217,10 @@ $res = Db::table('user')->select('gender', Db::raw('COUNT(0) AS `count`'))->grou
|
||||
|
||||
### 強制索引
|
||||
|
||||
資料庫出現的慢查問題, 90% 以上是索引不對, 其中有部分查詢是因為資料庫伺服器的 `查詢優化器` 沒有使用最佳索引, 這時候就需要使用強制強制索引:
|
||||
資料庫出現的慢查問題, 90% 以上是索引不對, 其中有部分查詢是因為資料庫伺服器的 `查詢優化器` 沒有使用最佳索引, 這時候就需要使用強制索引:
|
||||
|
||||
```php
|
||||
Db::table(Db::raw(sprintf("{$table} FORCE INDEX({$index})");
|
||||
|
||||
Db::table(Db::raw("{$table} FORCE INDEX({$index})"));
|
||||
```
|
||||
|
||||
### 原生方法
|
||||
|
@ -339,3 +339,24 @@ try{
|
||||
Db::rollBack();
|
||||
}
|
||||
```
|
||||
|
||||
## 輸出剛剛執行的 SQL
|
||||
|
||||
> 當前方法僅能用於開發環境,線上部署前一定要去掉,不然會引起嚴重的記憶體洩露和資料混淆。
|
||||
|
||||
線上記錄 `SQL`,請使用 [事件監聽](/zh-cn/db/event?id=sql-執行監聽器)
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use Hyperf\DbConnection\Db;
|
||||
use App\Model\Book;
|
||||
|
||||
// 啟用 SQL 資料記錄功能
|
||||
Db::enableQueryLog();
|
||||
|
||||
$book = Book::query()->find(1);
|
||||
|
||||
// 列印最後一條 SQL 相關資料
|
||||
var_dump(Arr::last(Db::getQueryLog()));
|
||||
```
|
||||
|
@ -21,6 +21,8 @@ composer require hyperf/event
|
||||
|
||||
## 使用事件管理器
|
||||
|
||||
> 接下來我們會通過配置和註解兩種方式介紹監聽器,實際使用時,二者只需使用其一即可,如果既有註解又有配置,則會造成監聽器被多次觸發。
|
||||
|
||||
### 定義一個事件
|
||||
|
||||
一個事件其實就是一個用於管理狀態資料的普通類,觸發時將應用資料傳遞到事件裡,然後監聽器對事件類進行操作,一個事件可被多個監聽器監聽。
|
||||
@ -181,4 +183,3 @@ class UserService
|
||||
> `1.1.6` 版本及更新的版本已優化此問題
|
||||
|
||||
在 `1.1.6` 版本之前,因為 `BootApplication` 是在 `Command` 初始化 和 `Server` 啟動前觸發,所以當前環境一定是非協程環境,一旦使用了協程 `API`,則會導致啟動失敗。
|
||||
|
||||
|
@ -122,3 +122,67 @@ $client = make(Client::class, [
|
||||
],
|
||||
]);
|
||||
```
|
||||
|
||||
## 使用 `ClassMap` 替換 `GuzzleHttp\Client`
|
||||
|
||||
如果第三方元件並沒有提供可以替換 `Handler` 的介面,我們也可以通過 `ClassMap` 功能,直接替換 `Client` 來達到將客戶端協程化的目的。
|
||||
|
||||
> 當然,也可以使用 SWOOLE_HOOK 達到相同的目的。
|
||||
|
||||
程式碼示例如下:
|
||||
|
||||
class_map/GuzzleHttp/Client.php
|
||||
|
||||
```php
|
||||
<?php
|
||||
namespace GuzzleHttp;
|
||||
|
||||
use GuzzleHttp\Psr7;
|
||||
use Hyperf\Guzzle\CoroutineHandler;
|
||||
use Hyperf\Utils\Coroutine;
|
||||
|
||||
class Client implements ClientInterface
|
||||
{
|
||||
// 程式碼省略其他不變的程式碼
|
||||
|
||||
public function __construct(array $config = [])
|
||||
{
|
||||
$inCoroutine = Coroutine::inCoroutine();
|
||||
if (!isset($config['handler'])) {
|
||||
// 對應的 Handler 可以按需選擇 CoroutineHandler 或 PoolHandler
|
||||
$config['handler'] = HandlerStack::create($inCoroutine ? new CoroutineHandler() : null);
|
||||
} elseif ($inCoroutine && $config['handler'] instanceof HandlerStack) {
|
||||
$config['handler']->setHandler(new CoroutineHandler());
|
||||
} elseif (!is_callable($config['handler'])) {
|
||||
throw new \InvalidArgumentException('handler must be a callable');
|
||||
}
|
||||
|
||||
// Convert the base_uri to a UriInterface
|
||||
if (isset($config['base_uri'])) {
|
||||
$config['base_uri'] = Psr7\uri_for($config['base_uri']);
|
||||
}
|
||||
|
||||
$this->configureDefaults($config);
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
config/autoload/annotations.php
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
|
||||
return [
|
||||
'scan' => [
|
||||
// ...
|
||||
'class_map' => [
|
||||
Client::class => BASE_PATH . '/class_map/GuzzleHttp/Client.php',
|
||||
],
|
||||
],
|
||||
];
|
||||
```
|
||||
|
124
docs/zh-tw/jet.md
Normal file
124
docs/zh-tw/jet.md
Normal file
@ -0,0 +1,124 @@
|
||||
# Jet
|
||||
|
||||
Jet 是一個統一模型的 RPC 客戶端,內建 JSONRPC 協議的適配,該元件可適用於所有的 PHP 環境,包括 PHP-FPM 和 Swoole 或 Hyperf。(在 Hyperf 環境下,目前仍建議直接使用 `hyperf/json-rpc` 元件來作為客戶端使用)
|
||||
|
||||
> 未來還會內建 gRPC 和 Tars 協議。
|
||||
|
||||
# 安裝
|
||||
|
||||
```bash
|
||||
composer require hyperf/jet
|
||||
```
|
||||
|
||||
# 快速開始
|
||||
|
||||
## 註冊協議
|
||||
|
||||
> 註冊協議不是必須的一個步驟,但您可以通過 ProtocolManager 管理所有的協議。
|
||||
|
||||
您可以通過 `Hyperf\Jet\ProtocolManager` 類來註冊管理任意的協議,每個協議會包含 Transporter, Packer, DataFormatter and PathGenerator 幾個基本的元件,您可以註冊一個 JSONRPC 協議,如下:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use Hyperf\Jet\DataFormatter\DataFormatter;
|
||||
use Hyperf\Jet\Packer\JsonEofPacker;
|
||||
use Hyperf\Jet\PathGenerator\PathGenerator;
|
||||
use Hyperf\Jet\ProtocolManager;
|
||||
use Hyperf\Jet\Transporter\StreamSocketTransporter;
|
||||
|
||||
ProtocolManager::register($protocol = 'jsonrpc', [
|
||||
ProtocolManager::TRANSPORTER => new StreamSocketTransporter(),
|
||||
ProtocolManager::PACKER => new JsonEofPacker(),
|
||||
ProtocolManager::PATH_GENERATOR => new PathGenerator(),
|
||||
ProtocolManager::DATA_FORMATTER => new DataFormatter(),
|
||||
]);
|
||||
```
|
||||
|
||||
## 註冊服務
|
||||
|
||||
> 註冊服務不是必須的一個步驟,但您可以通過 ServiceManager 管理所有的服務。
|
||||
|
||||
在您往 `Hyperf\Jet\ProtocolManager` 註冊了一個協議之後,您可以通過 `Hyperf\Jet\ServiceManager` 將協議繫結到任意的服務上,如下:
|
||||
|
||||
```php
|
||||
<?php
|
||||
use Hyperf\Jet\ServiceManager;
|
||||
|
||||
// 繫結 CalculatorService 與 jsonrpc 協議,同時設定靜態的節點資訊
|
||||
ServiceManager::register($service = 'CalculatorService', $protocol = 'jsonrpc', [
|
||||
ServiceManager::NODES => [
|
||||
[$host = '127.0.0.1', $port = 9503],
|
||||
],
|
||||
]);
|
||||
```
|
||||
|
||||
## 呼叫 RPC 方法
|
||||
|
||||
### 通過 ClientFactory 呼叫
|
||||
|
||||
在您註冊完協議與服務之後,您可以通過 `Hyperf/Jet/ClientFactory` 來獲得您的服務的客戶端,如下所示:
|
||||
|
||||
```php
|
||||
<?php
|
||||
use Hyperf\Jet\ClientFactory;
|
||||
|
||||
$clientFactory = new ClientFactory();
|
||||
$client = $clientFactory->create($service = 'CalculatorService', $protocol = 'jsonrpc');
|
||||
```
|
||||
|
||||
當您擁有 client 物件後,您可以通過該物件呼叫任意的遠端方法,如下:
|
||||
|
||||
```php
|
||||
// 呼叫遠端方法 `add` 並帶上引數 `1` 和 `2`
|
||||
// $result 即為遠端方法的返回值
|
||||
$result = $client->add(1, 2);
|
||||
```
|
||||
|
||||
當您呼叫一個不存在的遠端方法時,客戶端會丟擲一個 `Hyperf\Jet\Exception\ServerException` 異常。
|
||||
|
||||
### 通過自定義客戶端呼叫
|
||||
|
||||
您可以建立一個 `Hyperf\Jet\AbstractClient` 的子類作為自定義的客戶端類,來完成遠端方法的呼叫,比如,您希望定義一個 `CalculatorService` 服務的 `jsonrpc` 協議的客戶端類,您可以先定義一個 `CalculatorService` 類,如下所示:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use Hyperf\Jet\AbstractClient;
|
||||
use Hyperf\Jet\Packer\JsonEofPacker;
|
||||
use Hyperf\Jet\Transporter\StreamSocketTransporter;
|
||||
use Hyperf\Rpc\Contract\DataFormatterInterface;
|
||||
use Hyperf\Rpc\Contract\PackerInterface;
|
||||
use Hyperf\Rpc\Contract\PathGeneratorInterface;
|
||||
use Hyperf\Rpc\Contract\TransporterInterface;
|
||||
|
||||
/**
|
||||
* @method int add(int $a, int $b);
|
||||
*/
|
||||
class CalculatorService extends AbstractClient
|
||||
{
|
||||
// 定義 `CalculatorService` 作為 $service 引數的預設值
|
||||
public function __construct(
|
||||
string $service = 'CalculatorService',
|
||||
TransporterInterface $transporter = null,
|
||||
PackerInterface $packer = null,
|
||||
?DataFormatterInterface $dataFormatter = null,
|
||||
?PathGeneratorInterface $pathGenerator = null
|
||||
) {
|
||||
// 這裡指定 transporter,您仍然可以通過 ProtocolManager 來獲得 transporter 或從建構函式傳遞
|
||||
$transporter = new StreamSocketTransporter('127.0.0.1', 9503);
|
||||
// 這裡指定 packer,您仍然可以通過 ProtocolManager 來獲得 packer 或從建構函式傳遞
|
||||
$packer = new JsonEofPacker();
|
||||
parent::__construct($service, $transporter, $packer, $dataFormatter, $pathGenerator);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
現在,您可以通過該類來直接呼叫遠端方法了,如下所示:
|
||||
|
||||
```php
|
||||
// 呼叫遠端方法 `add` 並帶上引數 `1` 和 `2`
|
||||
// $result 即為遠端方法的返回值
|
||||
$client = new CalculatorService();
|
||||
$result = $client->add(1, 2);
|
||||
```
|
@ -71,19 +71,31 @@ return [
|
||||
### 獲取當前例項
|
||||
|
||||
```php
|
||||
$instance = new \Hyperf\Nacos\Instance();
|
||||
use Hyperf\Utils\ApplicationContext;
|
||||
use Hyperf\Nacos\Instance;
|
||||
|
||||
$container = ApplicationContext::getContainer();
|
||||
$instance = $container->get(Instance::class);
|
||||
```
|
||||
|
||||
### 獲取當前服務
|
||||
|
||||
```php
|
||||
$service = new \Hyperf\Nacos\Service();
|
||||
use Hyperf\Utils\ApplicationContext;
|
||||
use Hyperf\Nacos\Service;
|
||||
|
||||
$container = ApplicationContext::getContainer();
|
||||
$service = $container->get(Service::class);
|
||||
```
|
||||
|
||||
### 獲取一個服務的最優節點
|
||||
|
||||
```php
|
||||
$instance = make(NacosInstance::class);
|
||||
use Hyperf\Utils\ApplicationContext;
|
||||
use Hyperf\Nacos\Instance;
|
||||
|
||||
$container = ApplicationContext::getContainer();
|
||||
$instance = $container->get(Instance::class);
|
||||
|
||||
$service = new ServiceModel([
|
||||
'service_name' => 'hyperf',
|
||||
|
@ -251,6 +251,30 @@ class NsqCommand extends HyperfCommand
|
||||
}
|
||||
```
|
||||
|
||||
### NSQD HTTP API
|
||||
|
||||
> NSQD HTTP API Refer: https://nsq.io/components/nsqd.html
|
||||
|
||||
元件對 NSQD HTTP API 進行了封裝,您可以很方便的實現對 NSQD HTTP API 的呼叫。
|
||||
|
||||
比如,當您需要刪除某個 `Topic` 時,可以執行以下程式碼:
|
||||
|
||||
```php
|
||||
<?php
|
||||
use Hyperf\Utils\ApplicationContext;
|
||||
use Hyperf\Nsq\Nsqd\Topic;
|
||||
|
||||
$container = ApplicationContext::getContainer();
|
||||
|
||||
$client = $container->get(Topic::class);
|
||||
|
||||
$client->delete('hyperf.test');
|
||||
```
|
||||
|
||||
- `Hyperf\Nsq\Api\Topic` 類對應 `topic` 相關的 API;
|
||||
- `Hyperf\Nsq\Api\Channle` 類對應 `channel` 相關的 API;
|
||||
- `Hyperf\Nsq\Api\Api` 類對應 `ping`、`stats`、`config`、`debug` 等相關的 API;
|
||||
|
||||
## NSQ 協議
|
||||
|
||||
> https://nsq.io/clients/tcp_protocol_spec.html
|
||||
@ -319,7 +343,7 @@ client->server: AUTH
|
||||
|
||||
== pub ==
|
||||
note left of client: 傳送一條訊息
|
||||
client -> server: PUB <topic_name>
|
||||
client -> server: PUB~~~~ <topic_name>
|
||||
note left of client: 傳送多條訊息
|
||||
client -> server: MPUB
|
||||
note left of client: 傳送一條延時訊息
|
||||
@ -328,7 +352,7 @@ client -> server: DPUB
|
||||
|
||||
== sub ==
|
||||
note left of client: client 使用 channel 訂閱 topic
|
||||
note right of server: SUB 成功後, client 出於 RDY 0 階段
|
||||
note right of server: SUB 成功後, client 處於 RDY 0 階段
|
||||
client -> server: SUB <topic_name> <channel_name>
|
||||
note left of client: 使用 RDY 告訴 server 準備好消費 <count> 條訊息
|
||||
client -> server: RDY <count>
|
||||
|
@ -86,7 +86,7 @@ class FooProcess extends AbstractProcess
|
||||
// 您的程式碼 ...
|
||||
}
|
||||
|
||||
public function isEnable(): bool
|
||||
public function isEnable($server): bool
|
||||
{
|
||||
// 不跟隨服務啟動一同啟動
|
||||
return false;
|
||||
|
@ -128,3 +128,13 @@ composer dump-autoload -o
|
||||
> 當環境變數存在 SCAN_CACHEABLE 時,.env 中無法修改這個配置。
|
||||
|
||||
`2.0.0` 和 `2.0.1` 兩個版本,判斷檔案是否修改時,沒有判斷修改時間相等的情況,所以檔案修改後,立馬生成快取的情況(比如使用 `watcher` 元件時), 會導致程式碼無法及時生效。
|
||||
|
||||
## 語法錯誤導致服務無法啟動
|
||||
|
||||
當專案啟動時,丟擲類似於以下錯誤時
|
||||
|
||||
```
|
||||
Fatal error: Uncaught PhpParser\Error: Syntax error, unexpected T_STRING on line 27 in vendor/nikic/php-parser/lib/PhpParser/ParserAbstract.php:315
|
||||
```
|
||||
|
||||
可以執行指令碼 `composer analyse`,對專案進行靜態檢測,便可以找到出現問題的程式碼段。
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
## 替換 `Handler`
|
||||
|
||||
以下以小程式為例,
|
||||
以下以公眾號為例,
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -17,27 +17,27 @@ use EasyWeChat\Kernel\ServiceContainer;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\HandlerStack;
|
||||
use Hyperf\Guzzle\CoroutineHandler;
|
||||
use Hyperf\Guzzle\HandlerStackFactory;
|
||||
use Overtrue\Socialite\Providers\AbstractProvider;
|
||||
use Symfony\Component\HttpFoundation\ParameterBag;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
|
||||
$container = ApplicationContext::getContainer();
|
||||
|
||||
$app = Factory::miniProgram($config);
|
||||
$app = Factory::officialAccount($config);
|
||||
$handler = new CoroutineHandler();
|
||||
|
||||
// 設定 HttpClient,當前設定沒有實際效果,在資料請求時會被 guzzle_handler 覆蓋,但不保證 EasyWeChat 後面會修改這裡。
|
||||
// 設定 HttpClient,部分介面直接使用了 http_client。
|
||||
$config = $app['config']->get('http', []);
|
||||
$config['handler'] = $container->get(HandlerStackFactory::class)->create();
|
||||
$config['handler'] = $stack = HandlerStack::create($handler);
|
||||
$app->rebind('http_client', new Client($config));
|
||||
|
||||
// 重寫 Handler
|
||||
$app['guzzle_handler'] = new CoroutineHandler();
|
||||
// 部分介面在請求資料時,會根據 guzzle_handler 重置 Handler
|
||||
$app['guzzle_handler'] = $handler;
|
||||
|
||||
// 設定 OAuth 授權的 Guzzle 配置
|
||||
AbstractProvider::setGuzzleOptions([
|
||||
// 如果使用的是 OfficialAccount,則還需要設定以下引數
|
||||
$app->oauth->setGuzzleOptions([
|
||||
'http_errors' => false,
|
||||
'handler' => HandlerStack::create(new CoroutineHandler()),
|
||||
'handler' => $stack,
|
||||
]);
|
||||
```
|
||||
|
||||
@ -65,6 +65,7 @@ $xml = $this->request->getBody()->getContents();
|
||||
|
||||
```php
|
||||
<?php
|
||||
use Symfony\Component\HttpFoundation\HeaderBag;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
$get = $this->request->getQueryParams();
|
||||
@ -78,8 +79,9 @@ $files = [];
|
||||
foreach ($uploadFiles as $k => $v) {
|
||||
$files[$k] = $v->toArray();
|
||||
}
|
||||
$app['request'] = new Request($get, $post, [], $cookie, $files, $server, $xml);
|
||||
|
||||
$request = new Request($get, $post, [], $cookie, $files, $server, $xml);
|
||||
$request->headers = new HeaderBag($this->request->getHeaders());
|
||||
$app->rebind('request', $request);
|
||||
// Do something...
|
||||
|
||||
```
|
||||
|
@ -52,6 +52,8 @@ class TermSignalHandler implements SignalHandlerInterface
|
||||
|
||||
因為 Worker 程序接收的 SIGTERM 訊號被捕獲後,無法正常退出,所以使用者可以直接 `Ctrl + C` 退出,或者修改 `config/autoload/signal.php` 配置,如下:
|
||||
|
||||
> WorkerStopHandler 不適配於 CoroutineServer,如有需要請自行實現
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
@ -66,3 +68,63 @@ return [
|
||||
```
|
||||
|
||||
`WorkerStopHandler` 觸發後,會在所設定的 [max_wait_time](https://wiki.swoole.com/#/server/setting?id=max_wait_time) 配置時間後,關閉掉當前程序。
|
||||
|
||||
## 協程風格服務監聽器配置示例
|
||||
|
||||
> 以上預設的監聽器都是適配於非同步風格服務的,如果需要在協程風格服務下使用,可以按照以下自定義配置
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Kernel\Signal;
|
||||
|
||||
use Hyperf\AsyncQueue\Driver\Driver;
|
||||
use Hyperf\Contract\ConfigInterface;
|
||||
use Hyperf\Process\ProcessManager;
|
||||
use Hyperf\Server\ServerManager;
|
||||
use Hyperf\Signal\SignalHandlerInterface;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
class CoroutineServerStopHandler implements SignalHandlerInterface
|
||||
{
|
||||
/**
|
||||
* @var ContainerInterface
|
||||
*/
|
||||
protected $container;
|
||||
|
||||
/**
|
||||
* @var ConfigInterface
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
public function __construct(ContainerInterface $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
$this->config = $container->get(ConfigInterface::class);
|
||||
}
|
||||
|
||||
public function listen(): array
|
||||
{
|
||||
// 協程風格只會存在一個 Worker 程序,故這裡只需要監聽 WORKER 即可
|
||||
return [
|
||||
[self::WORKER, SIGTERM],
|
||||
[self::WORKER, SIGINT],
|
||||
];
|
||||
}
|
||||
|
||||
public function handle(int $signal): void
|
||||
{
|
||||
// 非同步佇列會使用以下引數迴圈 pop 訊息,v2.1以後版本會使用 ProcessManager::isRunning() 管理。
|
||||
Driver::$running = false;
|
||||
ProcessManager::setRunning(false);
|
||||
|
||||
foreach (ServerManager::list() as [$type, $server]) {
|
||||
// 迴圈關閉開啟的服務
|
||||
$server->shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
@ -17,6 +17,7 @@
|
||||
* [快速開始](zh-tw/quick-start/overview.md)
|
||||
* [常見問題](zh-tw/quick-start/questions.md)
|
||||
* [程式設計須知](zh-tw/quick-start/important.md)
|
||||
* [視訊教程](https://course.swoole-cloud.com/videos/5/new?from=hyperf.io)
|
||||
|
||||
* 核心架構
|
||||
|
||||
@ -58,8 +59,8 @@
|
||||
* [模型事件](zh-tw/db/event.md)
|
||||
* [模型快取](zh-tw/db/model-cache.md)
|
||||
* [資料庫遷移](zh-tw/db/migration.md)
|
||||
* [極簡 DB 元件](zh-tw/db/db.md)
|
||||
* [修改器](zh-tw/db/mutators.md)
|
||||
* [極簡 DB 元件](zh-tw/db/db.md)
|
||||
|
||||
* 微服務
|
||||
|
||||
@ -67,14 +68,20 @@
|
||||
* [JSON RPC 服務](zh-tw/json-rpc.md)
|
||||
* [gRPC 服務](zh-tw/grpc.md)
|
||||
* [服務註冊](zh-tw/service-register.md)
|
||||
* [服務重試](zh-tw/retry.md)
|
||||
* [服務熔斷及降級](zh-tw/circuit-breaker.md)
|
||||
* [服務限流](zh-tw/rate-limit.md)
|
||||
* [配置中心](zh-tw/config-center.md)
|
||||
* [呼叫鏈追蹤](zh-tw/tracer.md)
|
||||
* [服務監控](zh-tw/metric.md)
|
||||
* [服務重試](zh-tw/retry.md)
|
||||
* [Nacos](zh-tw/nacos.md)
|
||||
* [Snowflake](zh-tw/snowflake.md)
|
||||
|
||||
* 網路服務
|
||||
|
||||
* [TCP 服務](zh-tw/tcp-server.md)
|
||||
* [WebSocket 服務](zh-tw/websocket-server.md)
|
||||
* [Socket.io 服務](zh-tw/socketio-server.md)
|
||||
|
||||
* 訊息佇列
|
||||
|
||||
* [Redis 非同步佇列](zh-tw/async-queue.md)
|
||||
@ -82,30 +89,30 @@
|
||||
* [Nats](zh-tw/nats.md)
|
||||
* [NSQ](zh-tw/nsq.md)
|
||||
|
||||
* 其它元件
|
||||
* 客戶端
|
||||
|
||||
* [連線池](zh-tw/pool.md)
|
||||
* [Redis 協程客戶端](zh-tw/redis.md)
|
||||
* [Guzzle HTTP 協程客戶端](zh-tw/guzzle.md)
|
||||
* [Elasticsearch 協程客戶端](zh-tw/elasticsearch.md)
|
||||
* [Consul 協程客戶端](zh-tw/consul.md)
|
||||
* [ETCD 協程客戶端](zh-tw/etcd.md)
|
||||
* [WebSocket 服務](zh-tw/websocket-server.md)
|
||||
* [WebSocket 協程客戶端](zh-tw/websocket-client.md)
|
||||
* [Socket.io 服務](zh-tw/socketio-server.md)
|
||||
* [Nacos](zh-tw/nacos.md)
|
||||
* [Jet](zh-tw/jet.md)
|
||||
|
||||
* 其它元件
|
||||
|
||||
* [連線池](zh-tw/pool.md)
|
||||
* [自定義程序](zh-tw/process.md)
|
||||
* [開發者工具](zh-tw/devtool.md)
|
||||
* [輔助類](zh-tw/utils.md)
|
||||
* [限流器](zh-tw/rate-limit.md)
|
||||
* [Swoole Tracker](zh-tw/swoole-tracker.md)
|
||||
* [定時任務](zh-tw/crontab.md)
|
||||
* [Task 機制](zh-tw/task.md)
|
||||
* [列舉類](zh-tw/constants.md)
|
||||
* [Snowflake](zh-tw/snowflake.md)
|
||||
* [重試](zh-tw/retry.md)
|
||||
* [訊號處理器](zh-tw/signal.md)
|
||||
* [ReactiveX](zh-tw/reactive-x.md)
|
||||
* [Watcher](zh-tw/watcher.md)
|
||||
* [開發者工具](zh-tw/devtool.md)
|
||||
* [Swoole Tracker](zh-tw/swoole-tracker.md)
|
||||
|
||||
* 應用部署
|
||||
|
||||
|
@ -119,7 +119,7 @@ WORKDIR /opt/www
|
||||
|
||||
RUN composer install --no-dev \
|
||||
&& composer dump-autoload -o \
|
||||
&& php /opt/www/bin/hyperf.php di:init-proxy
|
||||
&& php /opt/www/bin/hyperf.php
|
||||
|
||||
EXPOSE 9501
|
||||
|
||||
|
78
docs/zh-tw/tcp-server.md
Normal file
78
docs/zh-tw/tcp-server.md
Normal file
@ -0,0 +1,78 @@
|
||||
# TCP 服務
|
||||
|
||||
框架預設提供建立 `TCP/UDP` 服務的能力。只需要進行簡易的配置,便可使用。
|
||||
|
||||
## 使用 TCP 服務
|
||||
|
||||
> UDP 服務請自行修改配置
|
||||
|
||||
### 建立 TcpServer 類
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use Hyperf\Contract\OnReceiveInterface;
|
||||
|
||||
class TcpServer implements OnReceiveInterface
|
||||
{
|
||||
public function onReceive($server, int $fd, int $fromId, string $data): void
|
||||
{
|
||||
$server->send($fd, 'recv:' . $data);
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### 建立對應配置
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Hyperf\Server\Server;
|
||||
use Hyperf\Server\SwooleEvent;
|
||||
|
||||
return [
|
||||
// 刪除其他不相關的配置項
|
||||
'servers' => [
|
||||
[
|
||||
'name' => 'tcp',
|
||||
'type' => Server::SERVER_BASE,
|
||||
'host' => '0.0.0.0',
|
||||
'port' => 9504,
|
||||
'sock_type' => SWOOLE_SOCK_TCP,
|
||||
'callbacks' => [
|
||||
SwooleEvent::ON_RECEIVE => [App\Controller\TcpServer::class, 'onReceive'],
|
||||
],
|
||||
'settings' => [
|
||||
// 按需配置
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
```
|
||||
|
||||
### 實現客戶端
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
$client = new \Swoole\Client(SWOOLE_SOCK_TCP);
|
||||
$client->connect('127.0.0.1', 9504);
|
||||
$client->send('Hello World.');
|
||||
$ret = $client->recv(); // recv:Hello World.
|
||||
```
|
||||
|
||||
## 事件
|
||||
|
||||
| 事件 | 備註 |
|
||||
| :---------------------: | :--------------: |
|
||||
| SwooleEvent::ON_CONNECT | 監聽連線進入事件 |
|
||||
| SwooleEvent::ON_RECEIVE | 監聽資料接收事件 |
|
||||
| SwooleEvent::ON_CLOSE | 監聽連線關閉事件 |
|
@ -52,7 +52,7 @@ return [
|
||||
|
||||
釋出 Translation 元件的檔案:
|
||||
|
||||
```php
|
||||
```bash
|
||||
php bin/hyperf.php vendor:publish hyperf/translation
|
||||
```
|
||||
|
||||
@ -349,7 +349,6 @@ if ($errors->has('foo')) {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## 驗證規則
|
||||
|
||||
下面是有效規則及其函式列表:
|
||||
|
@ -80,7 +80,7 @@ class WebSocketController implements OnMessageInterface, OnOpenInterface, OnClos
|
||||
}
|
||||
```
|
||||
|
||||
接下來啟動 Server,便能看到對應啟動了一個 WebSocket Server 並監聽於 9502 埠,此時您便可以通過各種 WebSocket Client 來進行連線和進行資料傳輸了。
|
||||
接下來啟動 Server,便能看到對應啟動了一個 WebSocket Server 並監聽於 9502 埠,此時您便可以通過各種 WebSocket Client 來進行連線和資料傳輸了。
|
||||
|
||||
```
|
||||
$ php bin/hyperf.php start
|
||||
@ -90,6 +90,34 @@ $ php bin/hyperf.php start
|
||||
[INFO] HTTP Server listening at 0.0.0.0:9501
|
||||
```
|
||||
|
||||
!> 當我們同時監聽了 HTTP Server 的 9501 埠和 WebSocket Server 的 9502 埠時, WebSocket Client 可以通過 9501 和 9502 兩個埠連線 WebSocket Server,即連線 `ws://0.0.0.0:9501` 和 `ws://0.0.0.0:9502` 都可以成功。
|
||||
|
||||
因為 Swoole\WebSocket\Server 繼承自 Swoole\Http\Server,可以使用 HTTP 觸發所有 WebSocket 的推送,瞭解詳情可檢視 [Swoole 文件](https://wiki.swoole.com/#/websocket_server?id=websocketserver) onRequest 回撥部分。
|
||||
|
||||
如需關閉,可以修改 `config/autoload/server.php` 檔案給 `http` 服務中增加 `open_websocket_protocol` 配置項。
|
||||
|
||||
```php
|
||||
<?php
|
||||
return [
|
||||
// 這裡省略了該檔案的其它配置
|
||||
'servers' => [
|
||||
[
|
||||
'name' => 'http',
|
||||
'type' => Server::SERVER_HTTP,
|
||||
'host' => '0.0.0.0',
|
||||
'port' => 9501,
|
||||
'sock_type' => SWOOLE_SOCK_TCP,
|
||||
'callbacks' => [
|
||||
SwooleEvent::ON_REQUEST => [Hyperf\HttpServer\Server::class, 'onRequest'],
|
||||
],
|
||||
'settings' => [
|
||||
'open_websocket_protocol' => false,
|
||||
]
|
||||
],
|
||||
]
|
||||
];
|
||||
```
|
||||
|
||||
## 連線上下文
|
||||
|
||||
WebSocket 服務的 onOpen, onMessage, onClose 回撥並不在同一個協程下觸發,因此不能直接使用協程上下文儲存狀態資訊。WebSocket Server 元件提供了 **連線級** 的上下文,API 與協程上下文完全一樣。
|
||||
|
@ -35,10 +35,12 @@ parameters:
|
||||
- '#Unsafe usage of new static#'
|
||||
- '#Method Hyperf\\Contract\\Sendable::send#'
|
||||
- '#Variable .* in PHPDoc tag @var does not exist#'
|
||||
- '#Call to an undefined method Hyperf\\DbConnection\\Model\\Model::hydrate#'
|
||||
- '#Call to an undefined method Hyperf\\Database\\Model\\Model::hydrate#'
|
||||
- '#PHPDoc tag @param has invalid value#'
|
||||
- '#Static call to instance method Hyperf\\RpcServer\\Router\\Router::#'
|
||||
- '#Method Hyperf\\Utils\\Serializer\\ScalarNormalizer::denormalize\(\) should return array\|object but returns#'
|
||||
- '#Function get_debug_type invoked with 1 parameter, 0 required#'
|
||||
- '#gc_status not found#'
|
||||
- '#Call to an undefined method Hyperf\\Utils\\HigherOrderCollectionProxy::.*#'
|
||||
- '#Used function getSwooleTracker.* not found#'
|
||||
- '#Function getSwooleTracker.* not found#'
|
3
src/amqp/.gitattributes
vendored
3
src/amqp/.gitattributes
vendored
@ -1 +1,2 @@
|
||||
/tests export-ignore
|
||||
/tests export-ignore
|
||||
/.github export-ignore
|
||||
|
25
src/amqp/.github/workflows/release.yml
vendored
Normal file
25
src/amqp/.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
|
3
src/async-queue/.gitattributes
vendored
3
src/async-queue/.gitattributes
vendored
@ -1 +1,2 @@
|
||||
/tests export-ignore
|
||||
/tests export-ignore
|
||||
/.github export-ignore
|
||||
|
25
src/async-queue/.github/workflows/release.yml
vendored
Normal file
25
src/async-queue/.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
|
@ -29,6 +29,7 @@ abstract class Driver implements DriverInterface
|
||||
{
|
||||
/**
|
||||
* @var bool
|
||||
* @deprecated v2.1 use ProcessManager::isRunning() instead.
|
||||
*/
|
||||
public static $running = true;
|
||||
|
||||
|
3
src/cache/.gitattributes
vendored
3
src/cache/.gitattributes
vendored
@ -1 +1,2 @@
|
||||
/tests export-ignore
|
||||
/tests export-ignore
|
||||
/.github export-ignore
|
||||
|
25
src/cache/.github/workflows/release.yml
vendored
Normal file
25
src/cache/.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
|
59
src/cache/tests/Cases/RedisDriverTest.php
vendored
59
src/cache/tests/Cases/RedisDriverTest.php
vendored
@ -24,9 +24,12 @@ use Hyperf\Redis\Frequency;
|
||||
use Hyperf\Redis\Pool\PoolFactory;
|
||||
use Hyperf\Redis\Pool\RedisPool;
|
||||
use Hyperf\Redis\Redis;
|
||||
use Hyperf\Redis\RedisFactory;
|
||||
use Hyperf\Redis\RedisProxy;
|
||||
use Hyperf\Utils\ApplicationContext;
|
||||
use Hyperf\Utils\Packer\PhpSerializerPacker;
|
||||
use HyperfTest\Cache\Stub\Foo;
|
||||
use HyperfTest\Cache\Stub\SerializeRedisDriver;
|
||||
use Mockery;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
@ -88,6 +91,27 @@ class RedisDriverTest extends TestCase
|
||||
$this->assertSame(5, $redis->ttl('c:xxx'));
|
||||
}
|
||||
|
||||
public function testSerializeRedisCacheDriver()
|
||||
{
|
||||
$container = $this->getContainer();
|
||||
$driver = $container->get(CacheManager::class)->getDriver('serialize');
|
||||
|
||||
$this->assertNull($driver->get('xxx', null));
|
||||
$this->assertTrue($driver->set('xxx', 'yyy'));
|
||||
$this->assertSame('yyy', $driver->get('xxx'));
|
||||
|
||||
$id = uniqid();
|
||||
$obj = new Foo($id);
|
||||
$driver->set('xxx', $obj);
|
||||
$this->assertSame($id, $driver->get('xxx')->id);
|
||||
|
||||
$redis = $container->get(RedisFactory::class)->get('serialize');
|
||||
$res = $redis->get('c:xxx');
|
||||
|
||||
$redis = $container->get(RedisFactory::class)->get('default');
|
||||
$this->assertSame(unserialize($redis->get('c:xxx')), $res);
|
||||
}
|
||||
|
||||
public function testDelete()
|
||||
{
|
||||
$container = $this->getContainer();
|
||||
@ -113,6 +137,11 @@ class RedisDriverTest extends TestCase
|
||||
'packer' => PhpSerializerPacker::class,
|
||||
'prefix' => 'c:',
|
||||
],
|
||||
'serialize' => [
|
||||
'driver' => SerializeRedisDriver::class,
|
||||
'packer' => PhpSerializerPacker::class,
|
||||
'prefix' => 'c:',
|
||||
],
|
||||
],
|
||||
'redis' => [
|
||||
'default' => [
|
||||
@ -132,6 +161,27 @@ class RedisDriverTest extends TestCase
|
||||
'max_idle_time' => 60,
|
||||
],
|
||||
],
|
||||
'serialize' => [
|
||||
'host' => 'localhost',
|
||||
'auth' => null,
|
||||
'port' => 6379,
|
||||
'db' => 0,
|
||||
'timeout' => 0.0,
|
||||
'reserved' => null,
|
||||
'retry_interval' => 0,
|
||||
'options' => [
|
||||
// TODO: Removed (string) when php version >= 7.3
|
||||
\Redis::OPT_SERIALIZER => (string) \Redis::SERIALIZER_PHP,
|
||||
],
|
||||
'pool' => [
|
||||
'min_connections' => 1,
|
||||
'max_connections' => 10,
|
||||
'connect_timeout' => 10.0,
|
||||
'wait_timeout' => 3.0,
|
||||
'heartbeat' => -1,
|
||||
'max_idle_time' => 60,
|
||||
],
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
@ -159,6 +209,15 @@ class RedisDriverTest extends TestCase
|
||||
$poolFactory = new PoolFactory($container);
|
||||
$container->shouldReceive('get')->with(\Redis::class)->andReturn(new Redis($poolFactory));
|
||||
|
||||
$container->shouldReceive('make')->with(RedisProxy::class, Mockery::any())->andReturnUsing(function ($_, $args) use ($poolFactory) {
|
||||
return new RedisProxy($poolFactory, $args['pool']);
|
||||
});
|
||||
$container->shouldReceive('get')->with(RedisFactory::class)->andReturnUsing(function () use ($config) {
|
||||
return new RedisFactory($config);
|
||||
});
|
||||
$container->shouldReceive('make')->with(SerializeRedisDriver::class, Mockery::any())->andReturnUsing(function ($_, $args) use ($container) {
|
||||
return new SerializeRedisDriver($container, $args['config']);
|
||||
});
|
||||
ApplicationContext::setContainer($container);
|
||||
|
||||
return $container;
|
||||
|
25
src/cache/tests/Stub/SerializeRedisDriver.php
vendored
Normal file
25
src/cache/tests/Stub/SerializeRedisDriver.php
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
<?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\Cache\Stub;
|
||||
|
||||
use Hyperf\Cache\Driver\RedisDriver;
|
||||
use Hyperf\Redis\RedisFactory;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
class SerializeRedisDriver extends RedisDriver
|
||||
{
|
||||
public function __construct(ContainerInterface $container, array $config)
|
||||
{
|
||||
parent::__construct($container, $config);
|
||||
$this->redis = $container->get(RedisFactory::class)->get('serialize');
|
||||
}
|
||||
}
|
2
src/circuit-breaker/.gitattributes
vendored
Normal file
2
src/circuit-breaker/.gitattributes
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/tests export-ignore
|
||||
/.github export-ignore
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user