Merge branch 'hyperf:master' into english-changelog-update-up-to-v3.0.9

This commit is contained in:
Márcio Dias 2023-03-10 20:29:46 -03:00 committed by GitHub
commit 3fc66a3eec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 333 additions and 79 deletions

View File

@ -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

View File

@ -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') {

View File

@ -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

View File

@ -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;` 命名空间;
定义单个中间件:

View File

@ -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。

View File

@ -176,7 +176,8 @@ class IndexController
}
```
### 通过 `@Inject` 注解注入
### 通过 `#[Inject]` 注解注入
只需对对应的类属性通过 `@var` 声明参数的类型,并使用 `#[Inject]` 注解标记属性 `Hyperf` 会自动注入对应的对象或值。
> 使用 `#[Inject]` 注解时需 `use Hyperf\Di\Annotation\Inject;` 命名空间;

View File

@ -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;

View File

@ -254,7 +254,7 @@ composer test -- --filter=testUserDaoFirst
如果在编写测试时无法使用(或选择不使用)实际的依赖组件(DOC),可以用测试替身来代替。测试替身不需要和真正的依赖组件有完全一样的的行为方式;他只需要提供和真正的组件同样的 API 即可,这样被测系统就会以为它是真正的组件!
下面展示分别通过构造函数注入依赖、通过 `@Inject` 注释注入依赖的测试替身
下面展示分别通过构造函数注入依赖、通过 `#[Inject]` 注释注入依赖的测试替身
### 构造函数注入依赖的测试替身

View File

@ -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;` 命名空間;
定義單箇中間件:

View File

@ -176,7 +176,8 @@ class IndexController
}
```
### 通過 `@Inject` 註解注入
### 通過 #[Inject]` 註解注入
只需對對應的類屬性通過 `@var` 聲明參數的類型,並使用 `#[Inject]` 註解標記屬性 `Hyperf` 會自動注入對應的對象或值。
> 使用 `#[Inject]` 註解時需 `use Hyperf\Di\Annotation\Inject;` 命名空間;

View File

@ -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;

View File

@ -254,7 +254,7 @@ composer test -- --filter=testUserDaoFirst
如果在編寫測試時無法使用(或選擇不使用)實際的依賴組件(DOC),可以用測試替身來代替。測試替身不需要和真正的依賴組件有完全一樣的的行為方式;他只需要提供和真正的組件同樣的 API 即可,這樣被測系統就會以為它是真正的組件!
下面展示分別通過構造函數注入依賴、通過 `@Inject` 註釋注入依賴的測試替身
下面展示分別通過構造函數注入依賴、通過 `#[Inject]` 註釋注入依賴的測試替身
### 構造函數注入依賴的測試替身

View File

@ -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;` 名稱空間;
定義單箇中間件:

View File

@ -176,7 +176,8 @@ class IndexController
}
```
### 透過 `@Inject` 註解注入
### 透過 `#[Inject]` 註解注入
只需對對應的類屬性透過 `@var` 宣告引數的型別,並使用 `#[Inject]` 註解標記屬性 `Hyperf` 會自動注入對應的物件或值。
> 使用 `#[Inject]` 註解時需 `use Hyperf\Di\Annotation\Inject;` 名稱空間;

View File

@ -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;

View File

@ -254,7 +254,7 @@ composer test -- --filter=testUserDaoFirst
如果在編寫測試時無法使用(或選擇不使用)實際的依賴元件(DOC),可以用測試替身來代替。測試替身不需要和真正的依賴元件有完全一樣的的行為方式;他只需要提供和真正的元件同樣的 API 即可,這樣被測系統就會以為它是真正的元件!
下面展示分別透過建構函式注入依賴、透過 `@Inject` 註釋注入依賴的測試替身
下面展示分別透過建構函式注入依賴、透過 `#[Inject]` 註釋注入依賴的測試替身
### 建構函式注入依賴的測試替身

View 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;
}

View File

@ -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();
}
}
}
}
}

View 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();
}
}
}
}
}

View File

@ -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);
}
}

View File

@ -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));
}
/**

View File

@ -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;
}

View File

@ -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({

View 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;
}
}

View File

@ -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) {

View File

@ -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.
*

View 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']);
}
}

View 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);
}
}

View File

@ -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_', '_');

View File

@ -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')));