Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions docs/transports.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,21 @@ This package contains some frequently used encoders / decoders for you:

| Class | EncodingType<DataType> | Action |
|-------------------------|---------------------------------------|-------------------------------------------------------------------------------------|
| `EmptyBodyEncoder` | `EncoderInterface<null>` | Creates empty request body |
| `BinaryFileDecoder` | `DecoderInterface<BinaryFile>` | Parses file information from the HTTP response and returns a `BinaryFile` DTO |
| `FormUrlencodedEncoder` | `EncoderInterface<?array>` | Adds form urlencoded body and headers to request |
| `ContentTypeAwareEncoder` | `EncoderInterface<ContentTypeAwarePayload<T>>` | Decorator that wraps any encoder and sets the Content-Type header from the payload |
| `EmptyBodyEncoder` | `EncoderInterface<null>` | Creates empty request body |
| `FormUrlencodedDecoder` | `DecoderInterface<array>` | Converts form urlencoded response body to array |
| `JsonEncoder` | `EncoderInterface<?array>` | Adds json body and headers to request |
| `FormUrlencodedEncoder` | `EncoderInterface<?array>` | Adds form urlencoded body and headers to request |
| `JsonDecoder` | `DecoderInterface<array>` | Converts json response body to array |
| `JsonEncoder` | `EncoderInterface<?array>` | Adds json body and headers to request |
| `MultiPartEncoder` | `EncoderInterface<AbstractMultipartPart>` | Adds symfony/mime `AbstractMultipartPart`as HTTP body. Handy for form data + files. |
| `StreamEncoder` | `EncoderInterface<StreamInterface>` | Adds PSR-7 Stream as request body |
| `StreamDecoder` | `DecoderInterface<StreamInterface>` | Returns the PSR-7 Stream as response result |
| `RawEncoder` | `EncoderInterface<string>` | Adds raw string as request body |
| `RawDecoder` | `DecoderInterface<string>` | Returns the raw PSR-7 body string as response result |
| `ResourceStreamEncoder` | `EncoderInterface<ResourceStream>` | Adds `phpro/resource-stream` as request body |
| `RawEncoder` | `EncoderInterface<string>` | Adds raw string as request body |
| `ResourceStreamDecoder` | `DecoderInterface<ResourceStream>` | Returns `phpro/resource-stream` from response body |
| `ResourceStreamEncoder` | `EncoderInterface<ResourceStream>` | Adds `phpro/resource-stream` as request body |
| `ResponseDecoder` | `DecoderInterface<ResponseInterface>` | Returns the received PSR-7 response as result |
| `StreamDecoder` | `DecoderInterface<StreamInterface>` | Returns the PSR-7 Stream as response result |
| `StreamEncoder` | `EncoderInterface<StreamInterface>` | Adds PSR-7 Stream as request body |

## Built-in transport presets:

Expand Down
34 changes: 34 additions & 0 deletions src/Encoding/ContentType/ContentTypeAwareEncoder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

declare(strict_types=1);

namespace Phpro\HttpTools\Encoding\ContentType;

use Phpro\HttpTools\Encoding\EncoderInterface;
use Psr\Http\Message\RequestInterface;

/**
* @template T
*
* @implements EncoderInterface<ContentTypeAwarePayload<T>>
*/
final class ContentTypeAwareEncoder implements EncoderInterface
{
/**
* @param EncoderInterface<T> $encoder
*/
public function __construct(
private EncoderInterface $encoder,
) {
}

/**
* @param ContentTypeAwarePayload<T> $data
*/
public function __invoke(RequestInterface $request, $data): RequestInterface
{
$request = ($this->encoder)($request, $data->payload);

return $request->withHeader('Content-Type', $data->contentType);
}
}
20 changes: 20 additions & 0 deletions src/Encoding/ContentType/ContentTypeAwarePayload.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

declare(strict_types=1);

namespace Phpro\HttpTools\Encoding\ContentType;

/**
* @template T
*/
final readonly class ContentTypeAwarePayload
{
/**
* @param T $payload
*/
public function __construct(
public string $contentType,
public mixed $payload,
) {
}
}
47 changes: 47 additions & 0 deletions tests/Unit/Encoding/ContentType/ContentTypeAwareEncoderTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

declare(strict_types=1);

namespace Phpro\HttpTools\Tests\Unit\Encoding\ContentType;

use Phpro\HttpTools\Encoding\ContentType\ContentTypeAwareEncoder;
use Phpro\HttpTools\Encoding\ContentType\ContentTypeAwarePayload;
use Phpro\HttpTools\Encoding\Raw\RawEncoder;
use Phpro\HttpTools\Test\UseHttpFactories;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;

final class ContentTypeAwareEncoderTest extends TestCase
{
use UseHttpFactories;

#[Test]
public function it_can_encode_with_content_type(): void
{
$encoder = new ContentTypeAwareEncoder(
RawEncoder::createWithAutodiscoveredPsrFactories()
);
$request = $this->createRequest('POST', '/hello');
$payload = new ContentTypeAwarePayload('application/pdf', 'raw-content');

$actual = $encoder($request, $payload);

self::assertSame('raw-content', (string) $actual->getBody());
self::assertSame('application/pdf', $actual->getHeaderLine('Content-Type'));
}

#[Test]
public function it_overrides_content_type_set_by_inner_encoder(): void
{
$encoder = new ContentTypeAwareEncoder(
RawEncoder::createWithAutodiscoveredPsrFactories()
);
$request = $this->createRequest('POST', '/hello')
->withHeader('Content-Type', 'text/plain');
$payload = new ContentTypeAwarePayload('application/xml', 'raw-content');

$actual = $encoder($request, $payload);

self::assertSame('application/xml', $actual->getHeaderLine('Content-Type'));
}
}
Loading