diff --git a/composer.json b/composer.json index 242e8da..cf9b9a7 100644 --- a/composer.json +++ b/composer.json @@ -17,6 +17,13 @@ "require": { "php": "~8.4.0 || ~8.5.0", "ext-json": "*", + "cardinalby/content-disposition": "^1.1", + "league/uri": "^7.3", + "php-http/client-common": "^2.7", + "php-http/discovery": "^1.19", + "php-http/httplug": "^2.4", + "php-http/logger-plugin": "^1.3", + "php-http/message": "^1.16 || ^2.0", "php-standard-library/foundation": "^6.1", "php-standard-library/fun": "^6.1", "php-standard-library/hash": "^6.1", @@ -25,13 +32,7 @@ "php-standard-library/regex": "^6.1", "php-standard-library/result": "^6.1", "php-standard-library/type": "^6.1", - "cardinalby/content-disposition": "^1.1", - "league/uri": "^7.3", - "php-http/client-common": "^2.7", - "php-http/discovery": "^1.19", - "php-http/httplug": "^2.4", - "php-http/logger-plugin": "^1.3", - "php-http/message": "^1.16 || ^2.0", + "phpro/resource-stream": "^1.3", "psr/http-client-implementation": "^1.0", "psr/http-factory": "^1.0", "psr/http-factory-implementation": "^1.0", diff --git a/docs/transports.md b/docs/transports.md index 7dfc307..51eaac2 100644 --- a/docs/transports.md +++ b/docs/transports.md @@ -40,6 +40,8 @@ This package contains some frequently used encoders / decoders for you: | `StreamDecoder` | `DecoderInterface` | Returns the PSR-7 Stream as response result | | `RawEncoder` | `EncoderInterface` | Adds raw string as request body | | `RawDecoder` | `DecoderInterface` | Returns the raw PSR-7 body string as response result | +| `ResourceStreamEncoder` | `EncoderInterface` | Adds `phpro/resource-stream` as request body | +| `ResourceStreamDecoder` | `DecoderInterface` | Returns `phpro/resource-stream` from response body | | `ResponseDecoder` | `DecoderInterface` | Returns the received PSR-7 response as result | ## Built-in transport presets: diff --git a/src/Encoding/ResourceStream/ResourceStreamDecoder.php b/src/Encoding/ResourceStream/ResourceStreamDecoder.php new file mode 100644 index 0000000..3a0a482 --- /dev/null +++ b/src/Encoding/ResourceStream/ResourceStreamDecoder.php @@ -0,0 +1,26 @@ +> + */ +final class ResourceStreamDecoder implements DecoderInterface +{ + public static function createWithAutodiscoveredPsrFactories(): self + { + return new self(); + } + + public function __invoke(ResponseInterface $response): ResourceStream + { + return Psr7Stream::createFromResponse($response); + } +} diff --git a/src/Encoding/ResourceStream/ResourceStreamEncoder.php b/src/Encoding/ResourceStream/ResourceStreamEncoder.php new file mode 100644 index 0000000..a8e453d --- /dev/null +++ b/src/Encoding/ResourceStream/ResourceStreamEncoder.php @@ -0,0 +1,36 @@ +> + */ +final class ResourceStreamEncoder implements EncoderInterface +{ + public function __construct( + private StreamFactoryInterface $streamFactory, + ) { + } + + public static function createWithAutodiscoveredPsrFactories(): self + { + return new self( + Psr17FactoryDiscovery::findStreamFactory(), + ); + } + + public function __invoke(RequestInterface $request, $data): RequestInterface + { + return $request->withBody( + $this->streamFactory->createStreamFromResource($data->unwrap()), + ); + } +} diff --git a/tests/Unit/Encoding/ResourceStream/ResourceStreamDecoderTest.php b/tests/Unit/Encoding/ResourceStream/ResourceStreamDecoderTest.php new file mode 100644 index 0000000..9de357b --- /dev/null +++ b/tests/Unit/Encoding/ResourceStream/ResourceStreamDecoderTest.php @@ -0,0 +1,29 @@ +createResponse() + ->withBody($this->createStream($content = '{"hello": "world"}')); + + $decoded = $decoder($response); + + self::assertInstanceOf(ResourceStream::class, $decoded); + self::assertSame($content, $decoded->getContents()); + } +} diff --git a/tests/Unit/Encoding/ResourceStream/ResourceStreamEncoderTest.php b/tests/Unit/Encoding/ResourceStream/ResourceStreamEncoderTest.php new file mode 100644 index 0000000..49b1d8b --- /dev/null +++ b/tests/Unit/Encoding/ResourceStream/ResourceStreamEncoderTest.php @@ -0,0 +1,48 @@ +write($content = 'Hello world'); + $resourceStream->rewind(); + + $encoder = ResourceStreamEncoder::createWithAutodiscoveredPsrFactories(); + $request = $this->createRequest('POST', '/hello'); + + $actual = $encoder($request, $resourceStream); + + self::assertSame($request->getMethod(), $actual->getMethod()); + self::assertSame($request->getUri(), $actual->getUri()); + self::assertSame($content, (string) $actual->getBody()); + self::assertFalse($actual->hasHeader('Content-Type')); + } + + #[Test] + public function it_can_encode_resource_stream_without_rewinding(): void + { + $resourceStream = MemoryStream::create(); + $resourceStream->write($content = 'Hello world'); + + $encoder = ResourceStreamEncoder::createWithAutodiscoveredPsrFactories(); + $request = $this->createRequest('POST', '/hello'); + + $actual = $encoder($request, $resourceStream); + + self::assertSame($content, (string) $actual->getBody()); + } +}