123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288 |
- <?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\Testing;
- use Hyperf\Codec\Packer\JsonPacker;
- use Hyperf\Collection\Arr;
- use Hyperf\Context\Context;
- use Hyperf\Contract\ConfigInterface;
- use Hyperf\Contract\PackerInterface;
- use Hyperf\Dispatcher\HttpDispatcher;
- use Hyperf\ExceptionHandler\ExceptionHandlerDispatcher;
- use Hyperf\HttpMessage\Server\Request as Psr7Request;
- use Hyperf\HttpMessage\Server\Response as Psr7Response;
- use Hyperf\HttpMessage\Stream\SwooleStream;
- use Hyperf\HttpMessage\Uri\Uri;
- use Hyperf\HttpServer\MiddlewareManager;
- use Hyperf\HttpServer\ResponseEmitter;
- use Hyperf\HttpServer\Router\Dispatched;
- use Hyperf\HttpServer\Server;
- use Hyperf\Support\Filesystem\Filesystem;
- use Hyperf\Testing\HttpMessage\Upload\UploadedFile;
- use Psr\Container\ContainerInterface;
- use Psr\Http\Message\ResponseInterface;
- use Psr\Http\Message\ServerRequestInterface;
- use Throwable;
- use function Hyperf\Collection\data_get;
- use function Hyperf\Coroutine\wait;
- class Client extends Server
- {
- protected PackerInterface $packer;
- protected float $waitTimeout = 10.0;
- protected string $baseUri = 'http://127.0.0.1/';
- public function __construct(ContainerInterface $container, ?PackerInterface $packer = null, $server = 'http')
- {
- parent::__construct(
- $container,
- $container->get(HttpDispatcher::class),
- $container->get(ExceptionHandlerDispatcher::class),
- $container->get(ResponseEmitter::class)
- );
- $this->packer = $packer ?? new JsonPacker();
- $this->initCoreMiddleware($server);
- $this->initBaseUri($server);
- }
- public function get(string $uri, array $data = [], array $headers = [])
- {
- $response = $this->request('GET', $uri, [
- 'headers' => $headers,
- 'query' => $data,
- ]);
- return $this->packer->unpack((string) $response->getBody());
- }
- public function post(string $uri, array $data = [], array $headers = [])
- {
- $response = $this->request('POST', $uri, [
- 'headers' => $headers,
- 'form_params' => $data,
- ]);
- return $this->packer->unpack((string) $response->getBody());
- }
- public function put(string $uri, array $data = [], array $headers = [])
- {
- $response = $this->request('PUT', $uri, [
- 'headers' => $headers,
- 'form_params' => $data,
- ]);
- return $this->packer->unpack((string) $response->getBody());
- }
- public function patch(string $uri, array $data = [], array $headers = [])
- {
- $response = $this->request('PATCH', $uri, [
- 'headers' => $headers,
- 'form_params' => $data,
- ]);
- return $this->packer->unpack((string) $response->getBody());
- }
- public function delete(string $uri, array $data = [], array $headers = [])
- {
- $response = $this->request('DELETE', $uri, [
- 'headers' => $headers,
- 'query' => $data,
- ]);
- return $this->packer->unpack((string) $response->getBody());
- }
- public function json(string $uri, array $data = [], array $headers = [])
- {
- $headers['Content-Type'] = 'application/json';
- $response = $this->request('POST', $uri, [
- 'headers' => $headers,
- 'json' => $data,
- ]);
- return $this->packer->unpack((string) $response->getBody());
- }
- public function file(string $uri, array $data = [], array $headers = [])
- {
- $multipart = [];
- if (Arr::isAssoc($data)) {
- $data = [$data];
- }
- foreach ($data as $item) {
- $name = $item['name'];
- $file = $item['file'];
- $multipart[] = [
- 'name' => $name,
- 'contents' => fopen($file, 'r'),
- 'filename' => basename($file),
- ];
- }
- $response = $this->request('POST', $uri, [
- 'headers' => $headers,
- 'multipart' => $multipart,
- ]);
- return $this->packer->unpack((string) $response->getBody());
- }
- public function request(string $method, string $path, array $options = [], ?callable $callable = null)
- {
- return wait(function () use ($method, $path, $options, $callable) {
- $callable && $callable();
- return $this->execute($this->initRequest($method, $path, $options));
- }, $this->waitTimeout);
- }
- public function sendRequest(ServerRequestInterface $psr7Request, ?callable $callable = null): ResponseInterface
- {
- return wait(function () use ($psr7Request, $callable) {
- $callable && $callable();
- return $this->execute($psr7Request);
- }, $this->waitTimeout);
- }
- public function initRequest(string $method, string $path, array $options = []): ServerRequestInterface
- {
- $query = $options['query'] ?? [];
- $params = $options['form_params'] ?? [];
- $json = $options['json'] ?? [];
- $headers = $options['headers'] ?? [];
- $multipart = $options['multipart'] ?? [];
- $parsePath = parse_url($path);
- $path = $parsePath['path'];
- $uriPathQuery = $parsePath['query'] ?? [];
- if (! empty($uriPathQuery)) {
- parse_str($uriPathQuery, $pathQuery);
- $query = array_merge($pathQuery, $query);
- }
- $data = $params;
- // Initialize PSR-7 Request and Response objects.
- $uri = (new Uri($this->baseUri . ltrim($path, '/')))->withQuery(http_build_query($query));
- $content = http_build_query($params);
- if ($method == 'POST' && data_get($headers, 'Content-Type') == 'application/json') {
- $content = json_encode($json, JSON_UNESCAPED_UNICODE);
- $data = $json;
- }
- $body = new SwooleStream($content);
- $request = new Psr7Request($method, $uri, $headers, $body);
- return $request->withQueryParams($query)
- ->withParsedBody($data)
- ->withUploadedFiles($this->normalizeFiles($multipart));
- }
- protected function execute(ServerRequestInterface $psr7Request): ResponseInterface
- {
- $this->persistToContext($psr7Request, new Psr7Response());
- $psr7Request = $this->coreMiddleware->dispatch($psr7Request);
- /** @var Dispatched $dispatched */
- $dispatched = $psr7Request->getAttribute(Dispatched::class);
- $middlewares = $this->middlewares;
- if ($dispatched->isFound()) {
- $registeredMiddlewares = MiddlewareManager::get($this->serverName, $dispatched->handler->route, $psr7Request->getMethod());
- $middlewares = array_merge($middlewares, $registeredMiddlewares);
- }
- $middlewares = MiddlewareManager::sortMiddlewares($middlewares);
- try {
- $psr7Response = $this->dispatcher->dispatch($psr7Request, $middlewares, $this->coreMiddleware);
- } catch (Throwable $throwable) {
- // Delegate the exception to exception handler.
- $psr7Response = $this->exceptionHandlerDispatcher->dispatch($throwable, $this->exceptionHandlers);
- }
- return $psr7Response;
- }
- protected function persistToContext(ServerRequestInterface $request, ResponseInterface $response)
- {
- Context::set(ServerRequestInterface::class, $request);
- Context::set(ResponseInterface::class, $response);
- }
- protected function initBaseUri(string $server): void
- {
- if ($this->container->has(ConfigInterface::class)) {
- $config = $this->container->get(ConfigInterface::class);
- $servers = $config->get('server.servers', []);
- foreach ($servers as $item) {
- if ($item['name'] == $server) {
- $this->baseUri = sprintf('http://127.0.0.1:%d/', (int) $item['port']);
- break;
- }
- }
- }
- }
- protected function normalizeFiles(array $multipart): array
- {
- $files = [];
- $fileSystem = $this->container->get(Filesystem::class);
- foreach ($multipart as $item) {
- if (isset($item['name'], $item['contents'], $item['filename'])) {
- $name = $item['name'];
- $contents = $item['contents'];
- $filename = $item['filename'];
- $dir = BASE_PATH . '/runtime/uploads';
- $tmpName = $dir . '/' . $filename;
- if (! is_dir($dir)) {
- $fileSystem->makeDirectory($dir);
- }
- $fileSystem->put($tmpName, $contents);
- $stats = fstat($contents);
- $files[$name] = new UploadedFile(
- $tmpName,
- $stats['size'],
- 0,
- $name
- );
- }
- }
- return $files;
- }
- protected function getStream(string $resource)
- {
- $stream = fopen('php://temp', 'r+');
- if ($resource !== '') {
- fwrite($stream, $resource);
- fseek($stream, 0);
- }
- return $stream;
- }
- }
|