mirror of
https://gitee.com/hyperf/hyperf.git
synced 2024-12-02 03:37:44 +08:00
Merge branch 'hyperf:master' into english-changelog-update-up-to-v3.0.9
This commit is contained in:
commit
3fc66a3eec
@ -1,5 +1,24 @@
|
||||
# v3.0.10 - TBD
|
||||
|
||||
## Fixed
|
||||
|
||||
- [#5501](https://github.com/hyperf/hyperf/pull/5501) Fixed bug that undefined `SWOOLE_HOOK_NATIVE_CURL` when swoole < `4.6`.
|
||||
|
||||
## Added
|
||||
|
||||
- [#5491](https://github.com/hyperf/hyperf/pull/5491) Added `charAt` method to both `Str` and `Stringable`.
|
||||
- [#5503](https://github.com/hyperf/hyperf/pull/5503) Added `Hyperf\Contract\JsonDeSerializable`.
|
||||
- [#5504](https://github.com/hyperf/hyperf/pull/5504) Added `Hyperf\Utils\Serializer\JsonDeNormalizer`.
|
||||
|
||||
## Optimized
|
||||
|
||||
- [#5493](https://github.com/hyperf/hyperf/pull/5493) Optimized code for service registration which support nacos `1.x` and `2.x`.
|
||||
- [#5494](https://github.com/hyperf/hyperf/pull/5494) Do not replace `Handler` when `native-curl` is supported.
|
||||
|
||||
## Changed
|
||||
|
||||
- [#5492](https://github.com/hyperf/hyperf/pull/5492) Renamed `CreatingListener` to `InitUidOnCreatingListener`.
|
||||
|
||||
# v3.0.9 - 2023-03-05
|
||||
|
||||
## Added
|
||||
@ -7,7 +26,7 @@
|
||||
- [#5467](https://github.com/hyperf/hyperf/pull/5467) Support `Google\Rpc\Status` for `GRPC`.
|
||||
- [#5472](https://github.com/hyperf/hyperf/pull/5472) Support `ulid` and `uuid` for Model.
|
||||
- [#5476](https://github.com/hyperf/hyperf/pull/5476) Added ArrayAccess to Stringable.
|
||||
- [#5478](https://github.com/hyperf/hyperf/pull/5478) Add isMatch method to Str and Stringable helpers.
|
||||
- [#5478](https://github.com/hyperf/hyperf/pull/5478) Added isMatch method to Str and Stringable helpers.
|
||||
|
||||
## Optimized
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
<link rel="manifest" href="/3.0/manifest.json">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<link rel="shortcut icon" href="/3.0/favicon.ico" />
|
||||
<link rel="stylesheet" href="//unpkg.com/docsify@4/themes/vue.css">
|
||||
<link rel="stylesheet" href="//unpkg.hyperf.wiki/docsify@4/themes/vue.css">
|
||||
<style>
|
||||
.app-name-link img {
|
||||
width: 16%;
|
||||
@ -21,10 +21,10 @@
|
||||
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script src="//unpkg.com/docsify@4/lib/docsify.min.js"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-php.min.js"></script>
|
||||
<script src="//unpkg.com/docsify-edit-on-github/index.js"></script>
|
||||
<script src="//unpkg.com/mermaid@9/dist/mermaid.min.js"></script>
|
||||
<script src="//unpkg.hyperf.wiki/docsify@4/lib/docsify.min.js"></script>
|
||||
<script src="//unpkg.hyperf.wiki/prismjs/components/prism-php.min.js"></script>
|
||||
<script src="//unpkg.hyperf.wiki/docsify-edit-on-github/index.js"></script>
|
||||
<script src="//unpkg.hyperf.wiki/mermaid@9/dist/mermaid.min.js"></script>
|
||||
<script>
|
||||
mermaid.initialize({ startOnLoad: false });
|
||||
|
||||
@ -121,10 +121,10 @@
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script src="//unpkg.com/docsify-copy-code@2/dist/docsify-copy-code.min.js"></script>
|
||||
<script src="//unpkg.com/docsify@4/lib/plugins/search.min.js"></script>
|
||||
<script src="//unpkg.com/docsify-plantuml/dist/docsify-plantuml.min.js"></script>
|
||||
<script src="//unpkg.com/docsify@4/lib/plugins/zoom-image.min.js"></script>
|
||||
<script src="//unpkg.hyperf.wiki/docsify-copy-code@2/dist/docsify-copy-code.min.js"></script>
|
||||
<script src="//unpkg.hyperf.wiki/docsify@4/lib/plugins/search.min.js"></script>
|
||||
<script src="//unpkg.hyperf.wiki/docsify-plantuml/dist/docsify-plantuml.min.js"></script>
|
||||
<script src="//unpkg.hyperf.wiki/docsify@4/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>
|
||||
<script>
|
||||
if (typeof navigator.serviceWorker !== 'undefined') {
|
||||
|
@ -12,7 +12,8 @@ const HOSTNAME_WHITELIST = [
|
||||
'fonts.gstatic.com',
|
||||
'fonts.googleapis.com',
|
||||
'cdn.jsdelivr.net',
|
||||
'unpkg.com'
|
||||
'unpkg.com',
|
||||
'unkpg.hyperf.wiki'
|
||||
]
|
||||
|
||||
// The Util Function to hack URLs of intercepted requests
|
||||
|
@ -63,11 +63,11 @@ Router::addGroup(
|
||||
### 通过注解定义
|
||||
|
||||
在通过注解定义路由时,您仅可通过注解的方式来定义中间件,对中间件的定义有两个注解,分别为:
|
||||
- `@Middleware` 注解为定义单个中间件时使用,在一个地方仅可定义一个该注解,不可重复定义
|
||||
- `@Middlewares` 注解为定义多个中间件时使用,在一个地方仅可定义一个该注解,然后通过在该注解内定义多个 `@Middleware` 注解实现多个中间件的定义
|
||||
- `#[Middleware]` 注解为定义单个中间件时使用,在一个地方仅可定义一个该注解,不可重复定义
|
||||
- `#[Middlewares]` 注解为定义多个中间件时使用,在一个地方仅可定义一个该注解,然后通过在该注解内定义多个 `#[Middleware]` 注解实现多个中间件的定义
|
||||
|
||||
> 使用 `@Middleware` 注解时需 `use Hyperf\HttpServer\Annotation\Middleware;` 命名空间;
|
||||
> 使用 `@Middlewares` 注解时需 `use Hyperf\HttpServer\Annotation\Middlewares;` 命名空间;
|
||||
> 使用 `#[Middleware]` 注解时需 `use Hyperf\HttpServer\Annotation\Middleware;` 命名空间;
|
||||
> 使用 `#[Middlewares]` 注解时需 `use Hyperf\HttpServer\Annotation\Middlewares;` 命名空间;
|
||||
|
||||
定义单个中间件:
|
||||
|
||||
|
@ -10,8 +10,8 @@ Hyperf 对系统环境有一些要求,当您使用 Swoole 网络引擎驱动
|
||||
|
||||
- PHP >= 8.0
|
||||
- 以下任一网络引擎
|
||||
- Swoole PHP 扩展 >= 4.5,并关闭了 `Short Name`
|
||||
- Swow PHP 扩展 (Beta)
|
||||
- [Swoole PHP 扩展](https://github.com/swoole/swoole-src) >= 4.5,并关闭了 `Short Name`
|
||||
- [Swow PHP 扩展](https://github.com/swow/swow)
|
||||
- JSON PHP 扩展
|
||||
- Pcntl PHP 扩展
|
||||
- OpenSSL PHP 扩展(如需要使用到 HTTPS)
|
||||
@ -19,7 +19,6 @@ Hyperf 对系统环境有一些要求,当您使用 Swoole 网络引擎驱动
|
||||
- Redis PHP 扩展 (如需要使用到 Redis 客户端)
|
||||
- Protobuf PHP 扩展 (如需要使用到 gRPC 服务端或客户端)
|
||||
|
||||
|
||||
## 安装 Hyperf
|
||||
|
||||
Hyperf 使用 [Composer](https://getcomposer.org) 来管理项目的依赖,在使用 Hyperf 之前,请确保你的运行环境已经安装好了 Composer。
|
||||
|
@ -176,7 +176,8 @@ class IndexController
|
||||
}
|
||||
```
|
||||
|
||||
### 通过 `@Inject` 注解注入
|
||||
### 通过 `#[Inject]` 注解注入
|
||||
|
||||
只需对对应的类属性通过 `@var` 声明参数的类型,并使用 `#[Inject]` 注解标记属性 ,`Hyperf` 会自动注入对应的对象或值。
|
||||
|
||||
> 使用 `#[Inject]` 注解时需 `use Hyperf\Di\Annotation\Inject;` 命名空间;
|
||||
|
@ -107,9 +107,9 @@ composer require hyperf/signal
|
||||
composer require symfony/serializer
|
||||
```
|
||||
|
||||
## Trait 内使用 `@Inject` 注入报错 `Error while injecting dependencies into ... No entry or class found ...`
|
||||
## Trait 内使用 `#[Inject]` 注入报错 `Error while injecting dependencies into ... No entry or class found ...`
|
||||
|
||||
若 Trait 通过 `@Inject @var` 注入属性, 同时子类里 `use` 了不同命名空间的同名类, 会导致 Trait 里类名被覆盖,进而导致注入失效:
|
||||
若 Trait 通过 `#[Inject] @var` 注入属性, 同时子类里 `use` 了不同命名空间的同名类, 会导致 Trait 里类名被覆盖,进而导致注入失效:
|
||||
|
||||
```php
|
||||
use Hyperf\HttpServer\Contract\ResponseInterface;
|
||||
|
@ -254,7 +254,7 @@ composer test -- --filter=testUserDaoFirst
|
||||
|
||||
如果在编写测试时无法使用(或选择不使用)实际的依赖组件(DOC),可以用测试替身来代替。测试替身不需要和真正的依赖组件有完全一样的的行为方式;他只需要提供和真正的组件同样的 API 即可,这样被测系统就会以为它是真正的组件!
|
||||
|
||||
下面展示分别通过构造函数注入依赖、通过 `@Inject` 注释注入依赖的测试替身
|
||||
下面展示分别通过构造函数注入依赖、通过 `#[Inject]` 注释注入依赖的测试替身
|
||||
|
||||
### 构造函数注入依赖的测试替身
|
||||
|
||||
|
@ -63,11 +63,11 @@ Router::addGroup(
|
||||
### 通過註解定義
|
||||
|
||||
在通過註解定義路由時,您僅可通過註解的方式來定義中間件,對中間件的定義有兩個註解,分別為:
|
||||
- `@Middleware` 註解為定義單箇中間件時使用,在一個地方僅可定義一個該註解,不可重複定義
|
||||
- `@Middlewares` 註解為定義多箇中間件時使用,在一個地方僅可定義一個該註解,然後通過在該註解內定義多個 `@Middleware` 註解實現多箇中間件的定義
|
||||
- `#[Middleware]` 註解為定義單箇中間件時使用,在一個地方僅可定義一個該註解,不可重複定義
|
||||
- `#[Middlewares]` 註解為定義多箇中間件時使用,在一個地方僅可定義一個該註解,然後通過在該註解內定義多個 `#[Middleware]` 註解實現多箇中間件的定義
|
||||
|
||||
> 使用 `@Middleware` 註解時需 `use Hyperf\HttpServer\Annotation\Middleware;` 命名空間;
|
||||
> 使用 `@Middlewares` 註解時需 `use Hyperf\HttpServer\Annotation\Middlewares;` 命名空間;
|
||||
> 使用 `#[Middleware]` 註解時需 `use Hyperf\HttpServer\Annotation\Middleware;` 命名空間;
|
||||
> 使用 `#[Middlewares]` 註解時需 `use Hyperf\HttpServer\Annotation\Middlewares;` 命名空間;
|
||||
|
||||
定義單箇中間件:
|
||||
|
||||
|
@ -176,7 +176,8 @@ class IndexController
|
||||
}
|
||||
```
|
||||
|
||||
### 通過 `@Inject` 註解注入
|
||||
### 通過 #[Inject]` 註解注入
|
||||
|
||||
只需對對應的類屬性通過 `@var` 聲明參數的類型,並使用 `#[Inject]` 註解標記屬性 ,`Hyperf` 會自動注入對應的對象或值。
|
||||
|
||||
> 使用 `#[Inject]` 註解時需 `use Hyperf\Di\Annotation\Inject;` 命名空間;
|
||||
|
@ -107,9 +107,9 @@ composer require hyperf/signal
|
||||
composer require symfony/serializer
|
||||
```
|
||||
|
||||
## Trait 內使用 `@Inject` 注入報錯 `Error while injecting dependencies into ... No entry or class found ...`
|
||||
## Trait 內使用 `#[Inject]` 注入報錯 `Error while injecting dependencies into ... No entry or class found ...`
|
||||
|
||||
若 Trait 通過 `@Inject @var` 注入屬性, 同時子類裏 `use` 了不同命名空間的同名類, 會導致 Trait 裏類名被覆蓋,進而導致注入失效:
|
||||
若 Trait 通過 `#[Inject] @var` 注入屬性, 同時子類裏 `use` 了不同命名空間的同名類, 會導致 Trait 裏類名被覆蓋,進而導致注入失效:
|
||||
|
||||
```php
|
||||
use Hyperf\HttpServer\Contract\ResponseInterface;
|
||||
|
@ -254,7 +254,7 @@ composer test -- --filter=testUserDaoFirst
|
||||
|
||||
如果在編寫測試時無法使用(或選擇不使用)實際的依賴組件(DOC),可以用測試替身來代替。測試替身不需要和真正的依賴組件有完全一樣的的行為方式;他只需要提供和真正的組件同樣的 API 即可,這樣被測系統就會以為它是真正的組件!
|
||||
|
||||
下面展示分別通過構造函數注入依賴、通過 `@Inject` 註釋注入依賴的測試替身
|
||||
下面展示分別通過構造函數注入依賴、通過 `#[Inject]` 註釋注入依賴的測試替身
|
||||
|
||||
### 構造函數注入依賴的測試替身
|
||||
|
||||
|
@ -63,11 +63,11 @@ Router::addGroup(
|
||||
### 透過註解定義
|
||||
|
||||
在透過註解定義路由時,您僅可透過註解的方式來定義中介軟體,對中介軟體的定義有兩個註解,分別為:
|
||||
- `@Middleware` 註解為定義單箇中間件時使用,在一個地方僅可定義一個該註解,不可重複定義
|
||||
- `@Middlewares` 註解為定義多箇中間件時使用,在一個地方僅可定義一個該註解,然後透過在該註解內定義多個 `@Middleware` 註解實現多箇中間件的定義
|
||||
- `#[Middleware]` 註解為定義單箇中間件時使用,在一個地方僅可定義一個該註解,不可重複定義
|
||||
- `#[Middlewares]` 註解為定義多箇中間件時使用,在一個地方僅可定義一個該註解,然後透過在該註解內定義多個 `#[Middleware]` 註解實現多箇中間件的定義
|
||||
|
||||
> 使用 `@Middleware` 註解時需 `use Hyperf\HttpServer\Annotation\Middleware;` 名稱空間;
|
||||
> 使用 `@Middlewares` 註解時需 `use Hyperf\HttpServer\Annotation\Middlewares;` 名稱空間;
|
||||
> 使用 `#[Middleware]` 註解時需 `use Hyperf\HttpServer\Annotation\Middleware;` 名稱空間;
|
||||
> 使用 `#[Middlewares]` 註解時需 `use Hyperf\HttpServer\Annotation\Middlewares;` 名稱空間;
|
||||
|
||||
定義單箇中間件:
|
||||
|
||||
|
@ -176,7 +176,8 @@ class IndexController
|
||||
}
|
||||
```
|
||||
|
||||
### 透過 `@Inject` 註解注入
|
||||
### 透過 `#[Inject]` 註解注入
|
||||
|
||||
只需對對應的類屬性透過 `@var` 宣告引數的型別,並使用 `#[Inject]` 註解標記屬性 ,`Hyperf` 會自動注入對應的物件或值。
|
||||
|
||||
> 使用 `#[Inject]` 註解時需 `use Hyperf\Di\Annotation\Inject;` 名稱空間;
|
||||
|
@ -107,9 +107,9 @@ composer require hyperf/signal
|
||||
composer require symfony/serializer
|
||||
```
|
||||
|
||||
## Trait 內使用 `@Inject` 注入報錯 `Error while injecting dependencies into ... No entry or class found ...`
|
||||
## Trait 內使用 `#[Inject]` 注入報錯 `Error while injecting dependencies into ... No entry or class found ...`
|
||||
|
||||
若 Trait 透過 `@Inject @var` 注入屬性, 同時子類裡 `use` 了不同名稱空間的同名類, 會導致 Trait 裡類名被覆蓋,進而導致注入失效:
|
||||
若 Trait 透過 `#[Inject] @var` 注入屬性, 同時子類裡 `use` 了不同名稱空間的同名類, 會導致 Trait 裡類名被覆蓋,進而導致注入失效:
|
||||
|
||||
```php
|
||||
use Hyperf\HttpServer\Contract\ResponseInterface;
|
||||
|
@ -254,7 +254,7 @@ composer test -- --filter=testUserDaoFirst
|
||||
|
||||
如果在編寫測試時無法使用(或選擇不使用)實際的依賴元件(DOC),可以用測試替身來代替。測試替身不需要和真正的依賴元件有完全一樣的的行為方式;他只需要提供和真正的元件同樣的 API 即可,這樣被測系統就會以為它是真正的元件!
|
||||
|
||||
下面展示分別透過建構函式注入依賴、透過 `@Inject` 註釋注入依賴的測試替身
|
||||
下面展示分別透過建構函式注入依賴、透過 `#[Inject]` 註釋注入依賴的測試替身
|
||||
|
||||
### 建構函式注入依賴的測試替身
|
||||
|
||||
|
17
src/contract/src/JsonDeSerializable.php
Normal file
17
src/contract/src/JsonDeSerializable.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Contract;
|
||||
|
||||
interface JsonDeSerializable
|
||||
{
|
||||
public static function jsonDeSerialize(mixed $data): static;
|
||||
}
|
@ -11,35 +11,9 @@ declare(strict_types=1);
|
||||
*/
|
||||
namespace Hyperf\DbConnection\Listener;
|
||||
|
||||
use Hyperf\Database\Model\Concerns\HasUlids;
|
||||
use Hyperf\Database\Model\Concerns\HasUuids;
|
||||
use Hyperf\Database\Model\Events\Creating;
|
||||
use Hyperf\Event\Contract\ListenerInterface;
|
||||
|
||||
class CreatingListener implements ListenerInterface
|
||||
/**
|
||||
* @deprecated It will be removed in v3.1
|
||||
*/
|
||||
class CreatingListener extends InitUidOnCreatingListener
|
||||
{
|
||||
public function listen(): array
|
||||
{
|
||||
return [
|
||||
Creating::class,
|
||||
];
|
||||
}
|
||||
|
||||
public function process(object $event): void
|
||||
{
|
||||
$model = $event->getModel();
|
||||
$class = get_class($model);
|
||||
|
||||
foreach (class_uses_recursive($class) as $trait) {
|
||||
if (! in_array($trait, [HasUuids::class, HasUlids::class])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($model->uniqueIds() as $column) {
|
||||
if (empty($model->{$column})) {
|
||||
$model->{$column} = $model->newUniqueId();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
45
src/db-connection/src/Listener/InitUidOnCreatingListener.php
Normal file
45
src/db-connection/src/Listener/InitUidOnCreatingListener.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\DbConnection\Listener;
|
||||
|
||||
use Hyperf\Database\Model\Concerns\HasUlids;
|
||||
use Hyperf\Database\Model\Concerns\HasUuids;
|
||||
use Hyperf\Database\Model\Events\Creating;
|
||||
use Hyperf\Event\Contract\ListenerInterface;
|
||||
|
||||
class InitUidOnCreatingListener implements ListenerInterface
|
||||
{
|
||||
public function listen(): array
|
||||
{
|
||||
return [
|
||||
Creating::class,
|
||||
];
|
||||
}
|
||||
|
||||
public function process(object $event): void
|
||||
{
|
||||
$model = $event->getModel();
|
||||
$class = get_class($model);
|
||||
|
||||
foreach (class_uses_recursive($class) as $trait) {
|
||||
if (! in_array($trait, [HasUuids::class, HasUlids::class])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($model->uniqueIds() as $column) {
|
||||
if (empty($model->{$column})) {
|
||||
$model->{$column} = $model->newUniqueId();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -16,16 +16,32 @@ use GuzzleHttp\HandlerStack;
|
||||
use Hyperf\Utils\Coroutine;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
/**
|
||||
* @property \Hyperf\Di\Container $container
|
||||
*/
|
||||
class ClientFactory
|
||||
{
|
||||
protected bool $runInSwoole = false;
|
||||
|
||||
protected int $nativeCurlHook = 0;
|
||||
|
||||
public function __construct(private ContainerInterface $container)
|
||||
{
|
||||
$this->runInSwoole = extension_loaded('swoole');
|
||||
if (defined('SWOOLE_HOOK_NATIVE_CURL')) {
|
||||
$this->nativeCurlHook = SWOOLE_HOOK_NATIVE_CURL;
|
||||
}
|
||||
}
|
||||
|
||||
public function create(array $options = []): Client
|
||||
{
|
||||
$stack = null;
|
||||
if (Coroutine::inCoroutine()) {
|
||||
|
||||
if (
|
||||
$this->runInSwoole
|
||||
&& Coroutine::inCoroutine()
|
||||
&& (\Swoole\Runtime::getHookFlags() & $this->nativeCurlHook) == 0
|
||||
) {
|
||||
$stack = HandlerStack::create(new CoroutineHandler());
|
||||
}
|
||||
|
||||
@ -35,6 +51,7 @@ class ClientFactory
|
||||
// Create by DI for AOP.
|
||||
return $this->container->make(Client::class, ['config' => $config]);
|
||||
}
|
||||
|
||||
return new Client($config);
|
||||
}
|
||||
}
|
||||
|
@ -200,7 +200,11 @@ class CoreMiddleware implements CoreMiddlewareInterface
|
||||
->withBody(new SwooleStream((string) $response));
|
||||
}
|
||||
|
||||
return $this->response()->withAddedHeader('content-type', 'text/plain')->withBody(new SwooleStream((string) $response));
|
||||
if ($this->response()->hasHeader('content-type')) {
|
||||
return $this->response()->withBody(new SwooleStream((string) $response));
|
||||
}
|
||||
|
||||
return $this->response()->withHeader('content-type', 'text/plain')->withBody(new SwooleStream((string) $response));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -124,7 +124,7 @@ class NacosDriver implements DriverInterface
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($response->getStatusCode() === 500 && strpos((string) $response->getBody(), 'not found') > 0) {
|
||||
if (in_array($response->getStatusCode(), [400, 500], true) && strpos((string) $response->getBody(), 'not found') > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -98,12 +98,12 @@ class HttpServer implements OnRequestInterface
|
||||
content="SwaggerUI"
|
||||
/>
|
||||
<title>SwaggerUI</title>
|
||||
<link rel="stylesheet" href="https://unpkg.com/swagger-ui-dist@4.5.0/swagger-ui.css" />
|
||||
<link rel="stylesheet" href="https://unpkg.hyperf.wiki/swagger-ui-dist@4.5.0/swagger-ui.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="swagger-ui"></div>
|
||||
<script src="https://unpkg.com/swagger-ui-dist@4.5.0/swagger-ui-bundle.js" crossorigin></script>
|
||||
<script src="https://unpkg.com/swagger-ui-dist@4.5.0/swagger-ui-standalone-preset.js" crossorigin></script>
|
||||
<script src="https://unpkg.hyperf.wiki/swagger-ui-dist@4.5.0/swagger-ui-bundle.js" crossorigin></script>
|
||||
<script src="https://unpkg.hyperf.wiki/swagger-ui-dist@4.5.0/swagger-ui-standalone-preset.js" crossorigin></script>
|
||||
<script>
|
||||
window.onload = () => {
|
||||
window.ui = SwaggerUIBundle({
|
||||
|
44
src/utils/src/Serializer/JsonDeNormalizer.php
Normal file
44
src/utils/src/Serializer/JsonDeNormalizer.php
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Utils\Serializer;
|
||||
|
||||
use Hyperf\Contract\NormalizerInterface;
|
||||
|
||||
class JsonDeNormalizer implements NormalizerInterface
|
||||
{
|
||||
public function normalize($object)
|
||||
{
|
||||
return $object;
|
||||
}
|
||||
|
||||
public function denormalize($data, string $class)
|
||||
{
|
||||
return match ($class) {
|
||||
'int' => (int) $data,
|
||||
'string' => (string) $data,
|
||||
'float' => (float) $data,
|
||||
'array' => (array) $data,
|
||||
'bool' => (bool) $data,
|
||||
'mixed' => $data,
|
||||
default => $this->from($data, $class),
|
||||
};
|
||||
}
|
||||
|
||||
private function from(mixed $data, string $class): mixed
|
||||
{
|
||||
if (method_exists($class, 'jsonDeSerialize')) {
|
||||
return $class::jsonDeSerialize($data);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
@ -181,6 +181,24 @@ class Str
|
||||
return static::$camelCache[$value] = lcfirst(static::studly($value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the character at the specified index.
|
||||
*
|
||||
* @param string $subject
|
||||
* @param int $index
|
||||
* @return null|string
|
||||
*/
|
||||
public static function charAt($subject, $index)
|
||||
{
|
||||
$length = mb_strlen($subject);
|
||||
|
||||
if ($index < 0 ? $index < -$length : $index > $length - 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return mb_substr($subject, $index, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a given string contains a given substring.
|
||||
*
|
||||
@ -370,19 +388,19 @@ class Str
|
||||
/**
|
||||
* Determine if a given string matches a given pattern.
|
||||
*
|
||||
* @param iterable<string>|string $pattern
|
||||
* @param iterable<string>|string $patterns
|
||||
* @param string $value
|
||||
* @return bool
|
||||
*/
|
||||
public static function isMatch($pattern, $value)
|
||||
public static function isMatch($patterns, $value)
|
||||
{
|
||||
$value = (string) $value;
|
||||
|
||||
if (! is_iterable($pattern)) {
|
||||
$pattern = [$pattern];
|
||||
if (! is_iterable($patterns)) {
|
||||
$patterns = [$patterns];
|
||||
}
|
||||
|
||||
foreach ($pattern as $pattern) {
|
||||
foreach ($patterns as $pattern) {
|
||||
$pattern = (string) $pattern;
|
||||
|
||||
if (preg_match($pattern, $value) === 1) {
|
||||
|
@ -113,6 +113,17 @@ class Stringable implements JsonSerializable, \Stringable, ArrayAccess
|
||||
return new static(basename($this->value, $suffix));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the character at the specified index.
|
||||
*
|
||||
* @param int $index
|
||||
* @return false|string
|
||||
*/
|
||||
public function charAt($index)
|
||||
{
|
||||
return Str::charAt($this->value, $index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the basename of the class path.
|
||||
*
|
||||
|
35
src/utils/tests/Serializer/Foo.php
Normal file
35
src/utils/tests/Serializer/Foo.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?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\Utils\Serializer;
|
||||
|
||||
use Hyperf\Contract\JsonDeSerializable;
|
||||
use JsonSerializable;
|
||||
|
||||
class Foo implements JsonDeSerializable, JsonSerializable
|
||||
{
|
||||
public function __construct(public int $id, public string $name)
|
||||
{
|
||||
}
|
||||
|
||||
public function jsonSerialize(): mixed
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'name' => $this->name,
|
||||
];
|
||||
}
|
||||
|
||||
public static function jsonDeSerialize(mixed $data): static
|
||||
{
|
||||
return new static($data['id'], $data['name']);
|
||||
}
|
||||
}
|
47
src/utils/tests/Serializer/JsonDeSerializableTest.php
Normal file
47
src/utils/tests/Serializer/JsonDeSerializableTest.php
Normal file
@ -0,0 +1,47 @@
|
||||
<?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\Utils\Serializer;
|
||||
|
||||
use Hyperf\Utils\Codec\Json;
|
||||
use Hyperf\Utils\Serializer\JsonDeNormalizer;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @coversNothing
|
||||
*/
|
||||
class JsonDeSerializableTest extends TestCase
|
||||
{
|
||||
public function testJsonDeSerializable()
|
||||
{
|
||||
$foo = new Foo(1, 'Hyperf');
|
||||
|
||||
$this->assertSame($json = '{"id":1,"name":"Hyperf"}', Json::encode($foo));
|
||||
|
||||
$foo = Foo::jsonDeSerialize(Json::decode($json));
|
||||
|
||||
$this->assertSame(1, $foo->id);
|
||||
$this->assertSame('Hyperf', $foo->name);
|
||||
}
|
||||
|
||||
public function testJsonDeNormalizer()
|
||||
{
|
||||
$normalizer = new JsonDeNormalizer();
|
||||
|
||||
$json = '{"id":1,"name":"Hyperf"}';
|
||||
|
||||
$foo = $normalizer->denormalize(Json::decode($json), Foo::class);
|
||||
|
||||
$this->assertSame(1, $foo->id);
|
||||
$this->assertSame('Hyperf', $foo->name);
|
||||
}
|
||||
}
|
@ -22,6 +22,16 @@ use Ramsey\Uuid\UuidInterface;
|
||||
*/
|
||||
class StrTest extends TestCase
|
||||
{
|
||||
public function testCharAt()
|
||||
{
|
||||
$this->assertEquals('р', Str::charAt('Привет, мир!', 1));
|
||||
$this->assertEquals('ち', Str::charAt('「こんにちは世界」', 4));
|
||||
$this->assertEquals('w', Str::charAt('Привет, world!', 8));
|
||||
$this->assertEquals('界', Str::charAt('「こんにちは世界」', -2));
|
||||
$this->assertEquals(null, Str::charAt('「こんにちは世界」', -200));
|
||||
$this->assertEquals(null, Str::charAt('Привет, мир!', 100));
|
||||
}
|
||||
|
||||
public function testSlug()
|
||||
{
|
||||
$res = Str::slug('hyperf_', '_');
|
||||
|
@ -21,6 +21,16 @@ use PHPUnit\Framework\TestCase;
|
||||
*/
|
||||
class StringableTest extends TestCase
|
||||
{
|
||||
public function testCharAt()
|
||||
{
|
||||
$this->assertEquals('р', $this->stringable('Привет, мир!')->charAt(1));
|
||||
$this->assertEquals('ち', $this->stringable('「こんにちは世界」')->charAt(4));
|
||||
$this->assertEquals('w', $this->stringable('Привет, world!')->charAt(8));
|
||||
$this->assertEquals('界', $this->stringable('「こんにちは世界」')->charAt(-2));
|
||||
$this->assertEquals(null, $this->stringable('「こんにちは世界」')->charAt(-200));
|
||||
$this->assertEquals(null, $this->stringable('Привет, мир!')->charAt('Привет, мир!', 100));
|
||||
}
|
||||
|
||||
public function testExactly()
|
||||
{
|
||||
$this->assertTrue($this->stringable('foo')->exactly($this->stringable('foo')));
|
||||
|
Loading…
Reference in New Issue
Block a user