Skip to content

Commit 7ecdd59

Browse files
committed
Add Body interface and implementations
Add Body implementations Remove Data body interface, common interface is not needed Add Content headers to Body Body is optional, add HttpMethods trait Refactored body implementations
1 parent 6a04619 commit 7ecdd59

15 files changed

+567
-154
lines changed

src/Body.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
namespace Http\Client;
4+
5+
use Psr\Http\Message\StreamInterface;
6+
7+
/**
8+
* Allows a more input types for body data
9+
*
10+
* @author Márk Sági-Kazár <[email protected]>
11+
*/
12+
interface Body
13+
{
14+
/**
15+
* Returns a set of headers which is needed to correctly send the body
16+
*
17+
* Note: these headers SHOULD be overwritten if any matching header is passed manually
18+
*
19+
* Content-Length is calculated automatically if possible
20+
*
21+
* @return array
22+
*/
23+
public function getContentHeaders();
24+
25+
/**
26+
* Convert data to a format which can be used to create a proper PSR-7 Stream
27+
*
28+
* @return string|StreamInterface
29+
*
30+
* @throws Exception
31+
*/
32+
public function toStreamable();
33+
}

src/Body/CombinedMultipart.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
namespace Http\Client\Body;
4+
5+
/**
6+
* Data and files converted to multipart form body
7+
*
8+
* @author Márk Sági-Kazár <[email protected]>
9+
*/
10+
class CombinedMultipart extends Multipart
11+
{
12+
/**
13+
* @var MultipartData
14+
*/
15+
protected $data;
16+
17+
/**
18+
* @var Files
19+
*/
20+
protected $files;
21+
22+
/**
23+
* @param array $data
24+
* @param array $files
25+
* @param string|null $boundary
26+
*/
27+
public function __construct(array $data, array $files, $boundary = null)
28+
{
29+
parent::__construct($boundary);
30+
31+
$this->data = new MultipartData($data, $this->boundary);
32+
$this->files = new Files($files, $this->boundary);
33+
}
34+
35+
/**
36+
* {@inheritdoc}
37+
*/
38+
public function toStreamable()
39+
{
40+
$body = $this->data->toStreamable();
41+
$body .= $this->files->toStreamable();
42+
43+
return $body;
44+
}
45+
}

src/Body/Files.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
3+
namespace Http\Client\Body;
4+
5+
use Http\Client\Exception\RuntimeException;
6+
7+
/**
8+
* Files converted to multipart form body
9+
*
10+
* @author Márk Sági-Kazár <[email protected]>
11+
*/
12+
class Files extends Multipart
13+
{
14+
/**
15+
* @var array
16+
*/
17+
protected $files;
18+
19+
/**
20+
* @param array $files
21+
* @param string|null $boundary
22+
*/
23+
public function __construct(array $files, $boundary = null)
24+
{
25+
$this->files = $files;
26+
27+
parent::__construct($boundary);
28+
}
29+
30+
/**
31+
* {@inheritdoc}
32+
*/
33+
public function toStreamable()
34+
{
35+
$body = '';
36+
37+
foreach ($this->files as $name => $file) {
38+
if (!is_file($file)) {
39+
throw new RuntimeException(sprintf('File "%s" does not exist', $file));
40+
}
41+
42+
$body .= sprintf(
43+
"--%s\r\nContent-Disposition: form-data; name=\"%s\"; filename=\"%s\"\r\n\r\n%s\r\n",
44+
$this->boundary,
45+
$name,
46+
basename($file),
47+
file_get_contents($file)
48+
);
49+
}
50+
51+
return $body;
52+
}
53+
}

src/Body/Multipart.php

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
namespace Http\Client\Body;
4+
5+
use Http\Client\Body;
6+
7+
/**
8+
* Basic multipart body
9+
*
10+
* @author Márk Sági-Kazár <[email protected]>
11+
*/
12+
abstract class Multipart implements Body
13+
{
14+
/**
15+
* @var string
16+
*/
17+
protected $boundary;
18+
19+
/**
20+
* @param string|null $boundary
21+
*/
22+
public function __construct($boundary = null)
23+
{
24+
if (is_null($boundary)) {
25+
$boundary = sha1(microtime());
26+
}
27+
28+
$this->boundary = $boundary;
29+
}
30+
31+
/**
32+
* {@inheritdoc}
33+
*/
34+
public function getContentHeaders()
35+
{
36+
return [
37+
'Content-Type' => 'multipart/form-data; boundary='.$this->boundary,
38+
];
39+
}
40+
}

src/Body/MultipartData.php

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?php
2+
3+
namespace Http\Client\Body;
4+
5+
/**
6+
* Data converted to multipart form body
7+
*
8+
* @author Márk Sági-Kazár <[email protected]>
9+
*/
10+
class MultipartData extends Multipart
11+
{
12+
/**
13+
* @var array
14+
*/
15+
protected $data;
16+
17+
/**
18+
* @param array $data
19+
* @param string|null $boundary
20+
*/
21+
public function __construct(array $data, $boundary = null)
22+
{
23+
$this->data = $data;
24+
25+
parent::__construct($boundary);
26+
}
27+
28+
/**
29+
* {@inheritdoc}
30+
*/
31+
public function toStreamable()
32+
{
33+
return $this->prepareData(null, $this->data);
34+
}
35+
36+
/**
37+
* @param string|integer|null $name
38+
* @param mixed $data
39+
*
40+
* @return string
41+
*/
42+
protected function prepareData($name, $data)
43+
{
44+
$body = '';
45+
46+
if (is_array($data)) {
47+
foreach ($data as $subName => $subData) {
48+
if (!is_null($name)) {
49+
$subName = sprintf('%s[%s]', $name, $subName);
50+
}
51+
52+
$body .= $this->prepareData($subName, $subData);
53+
}
54+
55+
return $body;
56+
}
57+
58+
$body .= sprintf(
59+
"--%s\r\nContent-Disposition: form-data; name=\"%s\"\r\n\r\n%s\r\n",
60+
$this->files->getBoundary(),
61+
$name,
62+
$data
63+
);
64+
65+
return $body;
66+
}
67+
}

src/Body/PlainText.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
namespace Http\Client\Body;
4+
5+
use Http\Client\Body;
6+
7+
/**
8+
* Plain text body
9+
*
10+
* @author Márk Sági-Kazár <[email protected]>
11+
*/
12+
class PlainText implements Body
13+
{
14+
/**
15+
* @var string
16+
*/
17+
protected $string;
18+
19+
/**
20+
* @param string $string
21+
*/
22+
public function __construct($string)
23+
{
24+
$this->string = $string;
25+
}
26+
27+
/**
28+
* {@inheritdoc}
29+
*/
30+
public function getContentHeaders()
31+
{
32+
return [
33+
'Content-Type' => 'text/plain',
34+
];
35+
}
36+
37+
/**
38+
* {@inheritdoc}
39+
*/
40+
public function toStreamable()
41+
{
42+
return $this->string;
43+
}
44+
}

src/Body/UrlencodedData.php

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
namespace Http\Client\Body;
4+
5+
use Http\Client\Body;
6+
7+
/**
8+
* @author Márk Sági-Kazár <[email protected]>
9+
*/
10+
class UrlencodedData implements Body
11+
{
12+
/**
13+
* @var array
14+
*/
15+
protected $data;
16+
17+
/**
18+
* @param array $data
19+
*/
20+
public function __construct(array $data)
21+
{
22+
$this->data = $data;
23+
}
24+
25+
/**
26+
* {@inheritdoc}
27+
*/
28+
public function getContentHeaders()
29+
{
30+
return [
31+
'Content-Type' => 'application/x-www-form-urlencoded',
32+
];
33+
}
34+
35+
/**
36+
* {@inheritdoc}
37+
*/
38+
public function toStreamable()
39+
{
40+
return http_build_query($this->data, null, '&');
41+
}
42+
}

src/Client.php

Lines changed: 0 additions & 13 deletions
This file was deleted.

src/Exception/HttpClientException.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,13 @@
22

33
namespace Http\Client\Exception;
44

5-
use Http\Client\Exception;
65
use Psr\Http\Message\RequestInterface;
76
use Psr\Http\Message\ResponseInterface;
87

98
/**
109
* @author GeLo <[email protected]>
1110
*/
12-
class HttpClientException extends \RuntimeException implements Exception
11+
class HttpClientException extends RuntimeException
1312
{
1413
/**
1514
* @var RequestInterface|null

src/Exception/MultiHttpClientException.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,12 @@
22

33
namespace Http\Client\Exception;
44

5-
use Http\Client\Exception;
65
use Psr\Http\Message\ResponseInterface;
76

87
/**
98
* @author GeLo <[email protected]>
109
*/
11-
class MultiHttpClientException extends \RuntimeException implements Exception
10+
class MultiHttpClientException extends RuntimeException
1211
{
1312
/**
1413
* @var HttpClientException[]

0 commit comments

Comments
 (0)