Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit c10f850

Browse filesBrowse files
committed
[HttpClient] add DecoratorTrait for response
1 parent b7a3c21 commit c10f850
Copy full SHA for c10f850

File tree

3 files changed

+195
-0
lines changed
Filter options

3 files changed

+195
-0
lines changed

‎src/Symfony/Component/HttpClient/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Component/HttpClient/CHANGELOG.md
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ CHANGELOG
77
* Add `HttpOptions::setHeader()` to add or replace a single header
88
* Allow mocking `start_time` info in `MockResponse`
99
* Add `MockResponse::fromFile()` and `JsonMockResponse::fromFile()` methods to help using fixtures files
10+
* Add `DecoratorTrait` for responses
1011

1112
7.0
1213
---
+98Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\HttpClient\Response;
13+
14+
use Symfony\Contracts\HttpClient\HttpClientInterface;
15+
use Symfony\Contracts\HttpClient\ResponseInterface;
16+
17+
/**
18+
* @author Cyril Vermande <https://github.com/cyve>
19+
*/
20+
trait DecoratorTrait
21+
{
22+
private ResponseInterface $response;
23+
24+
public function __construct(
25+
ResponseInterface $response,
26+
) {
27+
$this->response = $response;
28+
}
29+
30+
public function getStatusCode(): int
31+
{
32+
return $this->response->getStatusCode();
33+
}
34+
35+
public function getHeaders(bool $throw = true): array
36+
{
37+
return $this->response->getHeaders($throw);
38+
}
39+
40+
public function getContent(bool $throw = true): string
41+
{
42+
return $this->response->getContent($throw);
43+
}
44+
45+
public function toArray(bool $throw = true): array
46+
{
47+
return $this->response->toArray($throw);
48+
}
49+
50+
public function cancel(): void
51+
{
52+
$this->response->cancel();
53+
}
54+
55+
public function getInfo(string $type = null): mixed
56+
{
57+
return $this->response->getInfo($type);
58+
}
59+
60+
/**
61+
* @return resource
62+
*/
63+
public function toStream(bool $throw = true)
64+
{
65+
if ($throw) {
66+
// Ensure headers arrived
67+
$this->response->getHeaders();
68+
}
69+
70+
if ($this->response instanceof StreamableInterface) {
71+
return $this->response->toStream($throw);
72+
}
73+
74+
return StreamWrapper::createResource($this->response);
75+
}
76+
77+
/**
78+
* @internal
79+
*/
80+
public static function stream(HttpClientInterface $client, ResponseInterface|iterable $responses, float $timeout = null): \Generator
81+
{
82+
if ($responses instanceof ResponseInterface) {
83+
$responses = [$responses];
84+
}
85+
86+
$wrappedResponses = [];
87+
$responseMap = new \SplObjectStorage();
88+
89+
foreach ($responses as $response) {
90+
$responseMap[$response->response] = $response;
91+
$wrappedResponses[] = $response->response;
92+
}
93+
94+
foreach ($client->stream($wrappedResponses, $timeout) as $wrappedResponse => $chunk) {
95+
yield $responseMap[$wrappedResponse] => $chunk;
96+
}
97+
}
98+
}
+96Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\HttpClient\Tests\Response;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\HttpClient\Response\DecoratorTrait;
16+
use Symfony\Component\HttpClient\Response\MockResponse;
17+
use Symfony\Component\HttpClient\Response\ResponseStream;
18+
use Symfony\Contracts\HttpClient\HttpClientInterface;
19+
20+
/**
21+
* @author Cyril Vermande <https://github.com/cyve>
22+
*/
23+
class DecoratorTraitTest extends TestCase
24+
{
25+
private $subject;
26+
27+
protected function setUp(): void
28+
{
29+
$decorated = MockResponse::fromRequest(
30+
'GET',
31+
'https://symfony.com',
32+
[],
33+
new MockResponse(
34+
'{"foo":"bar"}',
35+
[
36+
'http_code' => 200,
37+
'response_headers' => ['Content-Type' => 'application/json'],
38+
],
39+
)
40+
);
41+
$this->subject = $this->getObjectForTrait(DecoratorTrait::class, [$decorated]);
42+
}
43+
44+
public function testShouldReturnDecoratedStatusCode()
45+
{
46+
$this->assertEquals(200, $this->subject->getStatusCode());
47+
}
48+
49+
public function testShouldReturnDecoratedHeaders()
50+
{
51+
$this->assertEquals(['content-type' => ['application/json']], $this->subject->getHeaders());
52+
}
53+
54+
public function testShouldReturnDecoratedContent()
55+
{
56+
$this->assertEquals('{"foo":"bar"}', $this->subject->getContent());
57+
}
58+
59+
public function testShouldReturnDecoratedContentInArray()
60+
{
61+
$this->assertEquals(['foo' => 'bar'], $this->subject->toArray());
62+
}
63+
64+
public function testShouldReturnDecoratedInfo()
65+
{
66+
$info = $this->subject->getInfo();
67+
$this->assertArrayHasKey('http_code', $info);
68+
$this->assertArrayHasKey('response_headers', $info);
69+
$this->assertArrayHasKey('http_method', $info);
70+
$this->assertArrayHasKey('url', $info);
71+
}
72+
73+
public function testShouldReturnDecoratedInfoByType()
74+
{
75+
$this->assertEquals('https://symfony.com', $this->subject->getInfo('url'));
76+
}
77+
78+
public function testShouldReturnDecoratedResponseAsStream()
79+
{
80+
$stream = $this->subject->toStream();
81+
$this->assertTrue(\is_resource($stream));
82+
$this->assertEquals('{"foo":"bar"}', stream_get_contents($stream));
83+
}
84+
85+
public function testShouldStreamTheDecoratedResponses()
86+
{
87+
$httpClient = $this->createMock(HttpClientInterface::class);
88+
$httpClient->method('stream')->willReturnCallback(fn ($responses, $timeout) => new ResponseStream(MockResponse::stream($responses, $timeout)));
89+
90+
foreach($this->subject::stream($httpClient, [$this->subject]) as $response => $chunk) {
91+
// Assert that the "stream()" method yield chunks from the decorated response, but with the wrapped response as key.
92+
$this->assertSame($response, $this->subject);
93+
break;
94+
}
95+
}
96+
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.