Skip to content

Commit d88aaaa

Browse files
[Contracts] add HttpClient\ApiClientInterface et al.
1 parent 1ad6f6f commit d88aaaa

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+5979
-3
lines changed

composer.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,13 @@
2828
"psr/link": "^1.0",
2929
"psr/log": "~1.0",
3030
"psr/simple-cache": "^1.0",
31-
"symfony/contracts": "^1.0.2",
31+
"symfony/contracts": "^1.1",
3232
"symfony/polyfill-ctype": "~1.8",
3333
"symfony/polyfill-intl-icu": "~1.0",
3434
"symfony/polyfill-intl-idn": "^1.10",
3535
"symfony/polyfill-mbstring": "~1.0",
3636
"symfony/polyfill-php72": "~1.5",
37-
"symfony/polyfill-php73": "^1.8"
37+
"symfony/polyfill-php73": "^1.11"
3838
},
3939
"replace": {
4040
"symfony/asset": "self.version",
@@ -55,6 +55,7 @@
5555
"symfony/finder": "self.version",
5656
"symfony/form": "self.version",
5757
"symfony/framework-bundle": "self.version",
58+
"symfony/http-client": "self.version",
5859
"symfony/http-foundation": "self.version",
5960
"symfony/http-kernel": "self.version",
6061
"symfony/inflector": "self.version",
@@ -101,8 +102,10 @@
101102
"doctrine/reflection": "~1.0",
102103
"doctrine/doctrine-bundle": "~1.4",
103104
"monolog/monolog": "~1.11",
105+
"nyholm/psr7": "^1.0",
104106
"ocramius/proxy-manager": "~0.4|~1.0|~2.0",
105107
"predis/predis": "~1.1",
108+
"psr/http-client": "^1.0",
106109
"egulias/email-validator": "~1.2,>=1.2.8|~2.0",
107110
"symfony/phpunit-bridge": "~3.4|~4.0",
108111
"symfony/security-acl": "~2.8|~3.0",
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
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;
13+
14+
use Symfony\Component\HttpClient\Response\ApiResponse;
15+
use Symfony\Component\HttpClient\Response\ApiResponseStream;
16+
use Symfony\Contracts\HttpClient\ApiClientInterface;
17+
use Symfony\Contracts\HttpClient\ApiResponseInterface;
18+
use Symfony\Contracts\HttpClient\ApiResponseStreamInterface;
19+
use Symfony\Contracts\HttpClient\HttpClientInterface;
20+
21+
/**
22+
* @see ApiClientInterface::OPTIONS_DEFAULTS for available options
23+
*
24+
* @author Nicolas Grekas <p@tchwork.com>
25+
*/
26+
final class ApiClient implements ApiClientInterface
27+
{
28+
use HttpClientTrait;
29+
30+
private $client;
31+
private $defaultOptions = [
32+
'headers' => [
33+
'accept' => ['application/json'],
34+
],
35+
] + ApiClientInterface::OPTIONS_DEFAULTS;
36+
37+
public function __construct(HttpClientInterface $client, array $defaultOptions = [])
38+
{
39+
$this->client = $client;
40+
41+
if ($defaultOptions) {
42+
[, $this->defaultOptions] = self::prepareRequest(null, null, $defaultOptions, $this->defaultOptions);
43+
}
44+
}
45+
46+
/**
47+
* {@inheritdoc}
48+
*/
49+
public function get(string $url, iterable $options = []): ApiResponseInterface
50+
{
51+
return $this->requestApi('GET', $url, $options);
52+
}
53+
54+
/**
55+
* {@inheritdoc}
56+
*/
57+
public function head(string $url, iterable $options = []): ApiResponseInterface
58+
{
59+
return $this->requestApi('HEAD', $url, $options);
60+
}
61+
62+
/**
63+
* {@inheritdoc}
64+
*/
65+
public function post(string $url, iterable $options = []): ApiResponseInterface
66+
{
67+
return $this->requestApi('POST', $url, $options);
68+
}
69+
70+
/**
71+
* {@inheritdoc}
72+
*/
73+
public function put(string $url, iterable $options = []): ApiResponseInterface
74+
{
75+
return $this->requestApi('PUT', $url, $options);
76+
}
77+
78+
/**
79+
* {@inheritdoc}
80+
*/
81+
public function patch(string $url, iterable $options = []): ApiResponseInterface
82+
{
83+
return $this->requestApi('PATCH', $url, $options);
84+
}
85+
86+
/**
87+
* {@inheritdoc}
88+
*/
89+
public function delete(string $url, iterable $options = []): ApiResponseInterface
90+
{
91+
return $this->requestApi('DELETE', $url, $options);
92+
}
93+
94+
/**
95+
* {@inheritdoc}
96+
*/
97+
public function options(string $url, iterable $options = []): ApiResponseInterface
98+
{
99+
return $this->requestApi('OPTIONS', $url, $options);
100+
}
101+
102+
/**
103+
* {@inheritdoc}
104+
*/
105+
public function complete($responses, float $timeout = null): ApiResponseStreamInterface
106+
{
107+
if ($responses instanceof ApiResponse) {
108+
$responses = [$responses];
109+
} elseif (!\is_iterable($responses)) {
110+
throw new \TypeError(sprintf('%s() expects parameter 1 to be iterable of ApiResponse objects, %s given.', __METHOD__, \is_object($responses) ? \get_class($responses) : \gettype($responses)));
111+
}
112+
113+
return new ApiResponseStream(ApiResponse::complete($this->client, $responses, $timeout));
114+
}
115+
116+
private function requestApi(string $method, string $url, iterable $options): ApiResponse
117+
{
118+
$options['buffer'] = true;
119+
[, $options] = self::prepareRequest(null, null, $options, $this->defaultOptions);
120+
121+
return new ApiResponse($this->client->request($method, $url, $options));
122+
}
123+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CHANGELOG
2+
=========
3+
4+
4.3.0
5+
-----
6+
7+
* added the component
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
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\Chunk;
13+
14+
use Symfony\Contracts\HttpClient\ChunkInterface;
15+
16+
/**
17+
* @author Nicolas Grekas <p@tchwork.com>
18+
*
19+
* @internal
20+
*/
21+
class DataChunk implements ChunkInterface
22+
{
23+
private $offset;
24+
private $content;
25+
26+
public function __construct(int $offset = 0, string $content = '')
27+
{
28+
$this->offset = $offset;
29+
$this->content = $content;
30+
}
31+
32+
/**
33+
* {@inheritdoc}
34+
*/
35+
public function isTimeout(): bool
36+
{
37+
return false;
38+
}
39+
40+
/**
41+
* {@inheritdoc}
42+
*/
43+
public function isFirst(): bool
44+
{
45+
return false;
46+
}
47+
48+
/**
49+
* {@inheritdoc}
50+
*/
51+
public function isLast(): bool
52+
{
53+
return false;
54+
}
55+
56+
/**
57+
* {@inheritdoc}
58+
*/
59+
public function getContent(): string
60+
{
61+
return $this->content;
62+
}
63+
64+
/**
65+
* {@inheritdoc}
66+
*/
67+
public function getOffset(): int
68+
{
69+
return $this->offset;
70+
}
71+
72+
/**
73+
* {@inheritdoc}
74+
*/
75+
public function getError(): ?string
76+
{
77+
return null;
78+
}
79+
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
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\Chunk;
13+
14+
use Symfony\Component\HttpClient\Exception\TransportException;
15+
use Symfony\Contracts\HttpClient\ChunkInterface;
16+
17+
/**
18+
* @author Nicolas Grekas <p@tchwork.com>
19+
*
20+
* @internal
21+
*/
22+
class ErrorChunk implements ChunkInterface
23+
{
24+
protected $didThrow;
25+
26+
private $offset;
27+
private $errorMessage;
28+
private $error;
29+
30+
/**
31+
* @param bool &$didThrow Allows monitoring when the $error has been thrown or not
32+
*/
33+
public function __construct(bool &$didThrow, int $offset, \Throwable $error = null)
34+
{
35+
$didThrow = false;
36+
$this->didThrow = &$didThrow;
37+
$this->offset = $offset;
38+
$this->error = $error;
39+
$this->errorMessage = null !== $error ? $error->getMessage() : 'Reading from the response stream reached the inactivity timeout.';
40+
}
41+
42+
/**
43+
* {@inheritdoc}
44+
*/
45+
public function isTimeout(): bool
46+
{
47+
$this->didThrow = true;
48+
49+
if (null !== $this->error) {
50+
throw new TransportException($this->errorMessage, 0, $this->error);
51+
}
52+
53+
return true;
54+
}
55+
56+
/**
57+
* {@inheritdoc}
58+
*/
59+
public function isFirst(): bool
60+
{
61+
$this->didThrow = true;
62+
throw new TransportException($this->errorMessage, 0, $this->error);
63+
}
64+
65+
/**
66+
* {@inheritdoc}
67+
*/
68+
public function isLast(): bool
69+
{
70+
$this->didThrow = true;
71+
throw new TransportException($this->errorMessage, 0, $this->error);
72+
}
73+
74+
/**
75+
* {@inheritdoc}
76+
*/
77+
public function getContent(): string
78+
{
79+
$this->didThrow = true;
80+
throw new TransportException($this->errorMessage, 0, $this->error);
81+
}
82+
83+
/**
84+
* {@inheritdoc}
85+
*/
86+
public function getOffset(): int
87+
{
88+
return $this->offset;
89+
}
90+
91+
/**
92+
* {@inheritdoc}
93+
*/
94+
public function getError(): ?string
95+
{
96+
return $this->errorMessage;
97+
}
98+
99+
public function __destruct()
100+
{
101+
if (!$this->didThrow) {
102+
$this->didThrow = true;
103+
throw new TransportException($this->errorMessage, 0, $this->error);
104+
}
105+
}
106+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
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\Chunk;
13+
14+
/**
15+
* @author Nicolas Grekas <p@tchwork.com>
16+
*
17+
* @internal
18+
*/
19+
class FirstChunk extends DataChunk
20+
{
21+
/**
22+
* {@inheritdoc}
23+
*/
24+
public function isFirst(): bool
25+
{
26+
return true;
27+
}
28+
}

0 commit comments

Comments
 (0)