Skip to content

Commit f714ede

Browse files
author
Greg Bowler
committed
Implement blob response type, placeholders for other types
1 parent 72e812d commit f714ede

16 files changed

+251
-12
lines changed

example/01-basic-fetch.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
->then(function(BodyResponse $response) {
1515
if(!$response->ok) {
1616
echo "Error fetching Github's API.";
17-
exit;
17+
exit(1);
1818
}
1919

2020
return $response->json();

example/02-post-request.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
->then(function(BodyResponse $response) {
2929
if(!$response->ok) {
3030
echo "Error posting to Postman Echo." . PHP_EOL;
31-
exit;
31+
exit(1);
3232
}
3333
// Postman Echo servers respond with a JSON representation of the request
3434
// that was received.

example/03-download-jpg.php

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
require(implode(DIRECTORY_SEPARATOR, ["..", "vendor", "autoload.php"]));
3+
4+
use Gt\Fetch\Http;
5+
use Gt\Fetch\Response\Blob;
6+
use Gt\Fetch\Response\BodyResponse;
7+
8+
/*
9+
* This example uses Cat-as-a-Service API to request a random photo of a cat.
10+
* See https://cataas.com/ for more information.
11+
*/
12+
13+
// Example: Download an image from the API and store in the temp directory.
14+
15+
$http = new Http();
16+
$http->fetch("https://cataas.com/cat")
17+
->then(function(BodyResponse $response) {
18+
if(!$response->ok) {
19+
echo "Error getting a cat." . PHP_EOL;
20+
exit(1);
21+
}
22+
23+
echo "Cat as a Service responded with a binary file with the following attributes:" . PHP_EOL;
24+
echo "Response size: " . $response->getHeaderLine("Content-Length") . PHP_EOL;
25+
echo "File type: " . $response->getHeaderLine("Content-Type") . PHP_EOL;
26+
return $response->blob();
27+
})
28+
->then(function(Blob $blob) {
29+
$extension = null;
30+
31+
switch($blob->type) {
32+
case "image/jpeg":
33+
$extension = "jpg";
34+
break;
35+
36+
case "image/png":
37+
$extension = "png";
38+
break;
39+
40+
default:
41+
echo $blob->type . " type is not supported." . PHP_EOL;
42+
exit(1);
43+
}
44+
45+
$file = new SplFileObject("/tmp/cat.$extension", "w");
46+
$bytesWritten = $file->fwrite($blob);
47+
echo "Written $bytesWritten bytes." . PHP_EOL;
48+
});
49+
50+
// To execute the above Promise(s), call wait() or all().
51+
$http->wait();

src/Http.php

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
use Gt\Curl\Curl;
55
use Gt\Curl\CurlMulti;
6+
use Gt\Fetch\Response\BodyResponse;
67
use Gt\Http\Uri;
78
use Http\Promise\Promise as HttpPromise;
89
use Http\Client\HttpClient;

src/RequestResolver.php

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
<?php
22
namespace Gt\Fetch;
33

4-
use Gt\Curl\Curl;
54
use Gt\Curl\CurlInterface;
6-
use Gt\Curl\CurlMulti;
75
use Gt\Curl\CurlMultiInterface;
6+
use Gt\Fetch\Response\BodyResponse;
87
use Gt\Http\Header\Parser;
98
use Psr\Http\Message\UriInterface;
109
use React\EventLoop\LoopInterface;

src/Response/ArrayBuffer.php

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
namespace Gt\Fetch\Response;
3+
4+
use SplFixedArray;
5+
6+
/**
7+
* @property-read int byteLength
8+
*/
9+
class ArrayBuffer extends SplFixedArray {
10+
public function transfer(
11+
self $oldBuffer,
12+
int $newByteLength = null
13+
):self {
14+
15+
}
16+
17+
public function slice(int $begin, int $end):self {
18+
19+
}
20+
}

src/Response/Blob.php

+123
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
<?php
2+
namespace Gt\Fetch\Response;
3+
4+
/**
5+
* @property-read int size
6+
* @property-read string type
7+
*/
8+
class Blob {
9+
const ENDINGS_TRANSPARENT = "transparent";
10+
const ENDINGS_NATIVE = "transparent";
11+
const PART_TYPE_ARRAY = "array";
12+
const PART_TYPE_ARRAYBUFFER = "arraybuffer";
13+
const PART_TYPE_BLOB = "blob";
14+
const PART_TYPE_STRING = "string";
15+
16+
protected $type;
17+
protected $endings;
18+
/** @var string */
19+
protected $content;
20+
21+
public function __construct($blobParts, array $options = []) {
22+
$this->type = $options["type"] ?? "";
23+
$this->endings = $options["endings"] ?? self::ENDINGS_TRANSPARENT;
24+
25+
$partType = $this->getBlobPartsType($blobParts);
26+
27+
switch($partType) {
28+
case self::PART_TYPE_ARRAY:
29+
$this->content = $this->loadArray($blobParts);
30+
break;
31+
32+
case self::PART_TYPE_ARRAYBUFFER:
33+
$this->content = $this->loadArrayBuffer($blobParts);
34+
break;
35+
36+
case self::PART_TYPE_BLOB:
37+
$this->content = $this->loadBlob($blobParts);
38+
break;
39+
40+
case self::PART_TYPE_STRING:
41+
$this->content = $this->loadString($blobParts);
42+
break;
43+
}
44+
}
45+
46+
public function __toString():string {
47+
return $this->getContent();
48+
}
49+
50+
public function __get(string $key) {
51+
switch($key) {
52+
case "size":
53+
return $this->size;
54+
break;
55+
56+
case "type":
57+
return $this->type;
58+
break;
59+
}
60+
}
61+
62+
public function getContent():string {
63+
return $this->content;
64+
}
65+
66+
protected function getBlobPartsType($blobParts):string {
67+
$type = null;
68+
69+
if(is_array($blobParts)) {
70+
return self::PART_TYPE_ARRAY;
71+
}
72+
73+
if($blobParts instanceof ArrayBuffer) {
74+
return self::PART_TYPE_ARRAYBUFFER;
75+
}
76+
77+
if($blobParts instanceof self) {
78+
return self::PART_TYPE_BLOB;
79+
}
80+
81+
if(is_string($blobParts)) {
82+
return self::PART_TYPE_STRING;
83+
}
84+
85+
if(is_null($type)) {
86+
throw new InvlidBlobPartTypeException($blobParts);
87+
}
88+
}
89+
90+
protected function loadArray(array $input):string {
91+
return $this->loadIterable($input);
92+
}
93+
94+
protected function loadArrayBuffer(ArrayBuffer $input):string {
95+
return $this->loadIterable($input);
96+
}
97+
98+
protected function loadBlob(self $input):string {
99+
return $input->content;
100+
}
101+
102+
protected function loadString(string $input):string {
103+
return $input;
104+
}
105+
106+
protected function loadIterable(iterable $input):string {
107+
$buffer = "";
108+
109+
foreach($input as $i) {
110+
if(self::ENDINGS_NATIVE) {
111+
$i = str_replace(
112+
["\n", "\r\n"],
113+
PHP_EOL,
114+
$i
115+
);
116+
}
117+
118+
$buffer .= $i;
119+
}
120+
121+
return $buffer;
122+
}
123+
}

src/BodyResponse.php src/Response/BodyResponse.php

+12-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
<?php
2-
namespace Gt\Fetch;
2+
namespace Gt\Fetch\Response;
33

44
use Gt\Curl\Curl;
55
use Gt\Curl\CurlInterface;
66
use Gt\Curl\JsonDecodeException;
7+
use Gt\Fetch\IntegrityMismatchException;
8+
use Gt\Fetch\InvalidIntegrityAlgorithmException;
9+
use Gt\Fetch\Promise;
710
use Gt\Http\Header\ResponseHeaders;
811
use Gt\Http\Response;
912
use Gt\Http\StatusCode;
@@ -88,10 +91,16 @@ public function arrayBuffer():Promise {
8891
public function blob():Promise {
8992
$newPromise = new Promise($this->loop);
9093

94+
$type = $this->getHeaderLine("Content-Type");
95+
9196
$deferredPromise = $this->deferred->promise();
9297
$deferredPromise->then(function(string $resolvedValue)
93-
use($newPromise) {
94-
$newPromise->resolve($resolvedValue);
98+
use($newPromise, $type) {
99+
$newPromise->resolve(
100+
new Blob($resolvedValue, [
101+
"type" => $type,
102+
])
103+
);
95104
});
96105

97106
return $newPromise;

src/BodyResponseFactory.php src/Response/BodyResponseFactory.php

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
<?php
2-
namespace Gt\Fetch;
2+
namespace Gt\Fetch\Response;
33

4-
use Gt\Http\Header\ResponseHeaders;
54
use Gt\Http\Response;
65

76
class BodyResponseFactory {

src/Response/FormData.php

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?php
2+
namespace Gt\Fetch\Response;
3+
4+
class FormData {
5+
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?php
2+
namespace Gt\Fetch\Response;
3+
4+
use Gt\Fetch\FetchException;
5+
6+
class InvlidBlobPartTypeException extends FetchException {}

src/Response/Json.php

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
namespace Gt\Fetch\Response;
3+
4+
use StdClass;
5+
6+
class Json extends StdClass {
7+
8+
}

src/Response/Text.php

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
namespace Gt\Fetch\Response;
3+
4+
class Text {
5+
/** @var string */
6+
protected $content;
7+
8+
public function __construct(string $content) {
9+
$this->content = $content;
10+
}
11+
12+
public function __toString():string {
13+
return $this->content;
14+
}
15+
}

test/unit/BodyResponseTest.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
use Gt\Curl\Curl;
55
use Gt\Curl\JsonDecodeException;
6-
use Gt\Fetch\BodyResponse;
6+
use Gt\Fetch\Response\BodyResponse;
77
use Gt\Fetch\Promise;
88
use PHPUnit\Framework\MockObject\MockObject;
99
use PHPUnit\Framework\TestCase;

test/unit/CurlOptBuilderTest.php

-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
use Gt\Fetch\NotAvailableServerSideException;
77
use Gt\Fetch\UnknownCurlOptException;
88
use PHPUnit\Framework\TestCase;
9-
use stdClass;
109

1110
class CurlOptBuilderTest extends TestCase {
1211
public function testInvalidKey() {

test/unit/HttpTest.php

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
<?php
2-
namespace Gt\Fetch;
2+
namespace Gt\Fetch\Test;
33

4+
use Gt\Fetch\Http;
5+
use Gt\Fetch\Promise;
6+
use Gt\Fetch\Response\BodyResponse;
47
use Gt\Fetch\Test\Helper\ResponseSimulator;
58
use Gt\Fetch\Test\Helper\TestCurl;
69
use Gt\Fetch\Test\Helper\TestCurlMulti;

0 commit comments

Comments
 (0)