diff --git a/src/Middleware/ClassicCoreMiddleware.php b/src/Middleware/ClassicCoreMiddleware.php index 0e80216..b5b55a9 100644 --- a/src/Middleware/ClassicCoreMiddleware.php +++ b/src/Middleware/ClassicCoreMiddleware.php @@ -28,6 +28,9 @@ use Singularity\HDK\Core\Service\UtilsService; * @author 李东云 * Powered by PhpStorm * Created on 2022/4/29 + * + * @deprecated + * @see CommonCoreMiddleware */ class ClassicCoreMiddleware extends CoreMiddleware { diff --git a/src/Middleware/ClassicStyleMiddleware.php b/src/Middleware/ClassicStyleMiddleware.php new file mode 100644 index 0000000..eec4773 --- /dev/null +++ b/src/Middleware/ClassicStyleMiddleware.php @@ -0,0 +1,30 @@ + + * Powered by PhpStorm + * Created on 2023/3/10 + */ + +namespace Singularity\HDK\Core\Middleware; + +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Server\RequestHandlerInterface; +use Singularity\HDK\Core\Service\ApiStyleService; + +class ClassicStyleMiddleware implements \Psr\Http\Server\MiddlewareInterface +{ + public function __construct(protected ApiStyleService $apiStyleService) + { + } + + /** + * @inheritDoc + */ + public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface + { + $this->apiStyleService->set(ApiStyleService::CLASSIC); + } +} \ No newline at end of file diff --git a/src/Middleware/CommonCoreMiddleware.php b/src/Middleware/CommonCoreMiddleware.php new file mode 100644 index 0000000..6fecbc8 --- /dev/null +++ b/src/Middleware/CommonCoreMiddleware.php @@ -0,0 +1,156 @@ + + * Powered by PhpStorm + * Created on 2022/4/29 + */ + +namespace Singularity\HDK\Core\Middleware; + +use Hyperf\Contract\Arrayable; +use Hyperf\Contract\Jsonable; +use Hyperf\Contract\LengthAwarePaginatorInterface; +use Hyperf\Di\Annotation\Inject; +use Hyperf\HttpMessage\Stream\SwooleStream; +use Hyperf\HttpServer\CoreMiddleware; +use Hyperf\Utils\Codec\Json; +use Lmc\HttpConstants\Header; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; +use Singularity\HDK\Core\Service\ApiStyleService; +use Singularity\HDK\Core\Service\UtilsService; + +/** + * Singularity\HDK\Core\Middleware\CommonCoreMiddleware@HDK-Core + * + * @author 李东云 + * Powered by PhpStorm + * Created on 2023/3/10 + */ +class CommonCoreMiddleware extends CoreMiddleware +{ + #[Inject] + private UtilsService $utilsService; + + #[Inject] + private ApiStyleService $apiStyleService; + + /** + * Transfer the non-standard response content to a standard response object. + * @template TKey of array-key + * @template TValue + * @param null|array|Arrayable|Jsonable|string $response + */ + protected function transferToClassicResponse($response, ServerRequestInterface $request): ResponseInterface + { + $code_name = config('common.response.code_name'); + $message_name = config('common.response.message_name'); + $data_name = config('common.response.data_name'); + // 分页数据 + if ($response instanceof LengthAwarePaginatorInterface) { + $paginator = $response; + $fact_response = $this->response()->withHeader('Per-Page', (string)$paginator->perPage())->withHeader( + 'Total', + (string)$paginator->total() + )->withHeader('Current-Page', (string)$paginator->currentPage())->withHeader( + 'Total-Pages', + (string)$paginator->hasPages() + ); + $fact_response = $this->utilsService->extendLinkToHeader($fact_response, $paginator->nextPageUrl(), 'next'); + $fact_response = $this->utilsService->extendLinkToHeader( + $fact_response, + $paginator->url($paginator->lastPage()), + 'last' + ); + $fact_response = $this->utilsService->extendLinkToHeader($fact_response, $paginator->url(1), 'first'); + $fact_response = $this->utilsService->extendLinkToHeader( + $fact_response, + $paginator->previousPageUrl(), + 'prev' + ); + return $fact_response->withAddedHeader(Header::CONTENT_TYPE, 'application/json')->withBody( + new SwooleStream( + Json::encode( + [ + $code_name => 200, + $message_name => 'ok', + $data_name => $response->items(), + 'meta' => [ + 'currentPage' => $paginator->currentPage(), + 'lastPage' => $paginator->lastPage(), + 'perPage' => $paginator->perPage(), + 'total' => $paginator->total(), + ], + ] + ) + ) + ); + } + // 普通数组 + if (is_array($response) || $response instanceof Arrayable) { + $response = [$code_name => 200, $message_name => 'ok', $data_name => $response]; + return $this->response()->withAddedHeader(Header::CONTENT_TYPE, 'application/json')->withBody( + new SwooleStream(Json::encode($response)) + ); + } + // 可 Json 化的数据结构 + if ($response instanceof Jsonable) { + $response = [$code_name => 200, $message_name => 'ok', $data_name => Json::decode((string)$response)]; + return $this->response()->withAddedHeader(Header::CONTENT_TYPE, 'application/json')->withBody( + new SwooleStream(Json::encode($response)) + ); + } + // 其他默认按字符串处理 + return $this->response()->withAddedHeader(Header::CONTENT_TYPE, 'text/plain')->withBody( + new SwooleStream((string)$response) + ); + } + + protected function transferToResponse($response, ServerRequestInterface $request): ResponseInterface + { + $style = $this->apiStyleService->get(); + + if ($style === ApiStyleService::RESTFUL) { + return $this->transferToRestfulResponse($response, $request); + } else { + return $this->transferToClassicResponse($response, $request); + } + } + + + /** + * @template TKey of array-key + * @template TValue + * @param null|array|Arrayable|Jsonable|string $response + * @param ServerRequestInterface $request + * @return ResponseInterface + */ + protected function transferToRestfulResponse($response, ServerRequestInterface $request): ResponseInterface + { + // 分页数据 + if ($response instanceof LengthAwarePaginatorInterface) { + $fact_response = $this->response() + ->withHeader('Per-Page', (string)$response->perPage()) + ->withHeader('Total', (string)$response->total()) + ->withHeader('Current-Page', (string)$response->currentPage()) + ->withHeader('Total-Pages', (string)$response->hasPages()); + $fact_response = $this->utilsService->extendLinkToHeader($fact_response, $response->nextPageUrl(), 'next'); + $fact_response = $this->utilsService->extendLinkToHeader( + $fact_response, + $response->url($response->lastPage()), + 'last' + ); + $fact_response = $this->utilsService->extendLinkToHeader($fact_response, $response->url(1), 'first'); + return $this->utilsService->extendLinkToHeader( + $fact_response, + $response->previousPageUrl(), + 'prev' + ); + } + + return parent::transferToResponse($response, $request); + } +} diff --git a/src/Middleware/RestStyleMiddleware.php b/src/Middleware/RestStyleMiddleware.php new file mode 100644 index 0000000..a9e939f --- /dev/null +++ b/src/Middleware/RestStyleMiddleware.php @@ -0,0 +1,31 @@ + + * Powered by PhpStorm + * Created on 2023/3/10 + */ + +namespace Singularity\HDK\Core\Middleware; + +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Server\MiddlewareInterface; +use Psr\Http\Server\RequestHandlerInterface; +use Singularity\HDK\Core\Service\ApiStyleService; + +class RestStyleMiddleware implements MiddlewareInterface +{ + public function __construct(protected ApiStyleService $apiStyleService) + { + } + + /** + * @inheritDoc + */ + public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface + { + $this->apiStyleService->set(ApiStyleService::RESTFUL); + } +} \ No newline at end of file diff --git a/src/Middleware/RestfulCoreMiddleware.php b/src/Middleware/RestfulCoreMiddleware.php index e0ded26..bdad674 100644 --- a/src/Middleware/RestfulCoreMiddleware.php +++ b/src/Middleware/RestfulCoreMiddleware.php @@ -24,6 +24,9 @@ use Singularity\HDK\Core\Service\UtilsService; * @author 李东云 * Powered by PhpStorm * Created on 2023/1/14 + * + * @deprecated + * @see CommonCoreMiddleware */ class RestfulCoreMiddleware extends CoreMiddleware { diff --git a/src/Service/ApiStyleService.php b/src/Service/ApiStyleService.php new file mode 100644 index 0000000..bcd03df --- /dev/null +++ b/src/Service/ApiStyleService.php @@ -0,0 +1,34 @@ + + * Powered by PhpStorm + * Created on 2023/3/10 + */ + +namespace Singularity\HDK\Core\Service; + +use Hyperf\Context\Context; + +class ApiStyleService +{ + public const RESTFUL = 'restful'; + public const CLASSIC = 'classic'; + + public function __construct() + { + Context::set(self::class, config('common.response.restful') ? self::RESTFUL : self::CLASSIC); + } + + public function set($style): static + { + Context::set(self::class, $style === self::RESTFUL ? self::RESTFUL : self::CLASSIC); + return $this; + } + + public function get(): string + { + return Context::get(self::class); + } +} \ No newline at end of file