-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathJsonRpcResponseCollection.php
113 lines (93 loc) · 3.67 KB
/
JsonRpcResponseCollection.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
<?php
namespace Bankiru\Api\BrowserKit;
use ScayTrase\Api\JsonRpc\Exception\JsonRpcProtocolException;
use ScayTrase\Api\JsonRpc\Exception\ResponseParseException;
use ScayTrase\Api\JsonRpc\JsonRpcNotificationResponse;
use ScayTrase\Api\JsonRpc\JsonRpcResponseInterface;
use ScayTrase\Api\JsonRpc\RequestTransformation;
use ScayTrase\Api\JsonRpc\SyncResponse;
use ScayTrase\Api\Rpc\Exception\RemoteCallFailedException;
use ScayTrase\Api\Rpc\ResponseCollectionInterface;
use ScayTrase\Api\Rpc\RpcRequestInterface;
use Symfony\Component\BrowserKit\Response;
final class JsonRpcResponseCollection implements \IteratorAggregate, ResponseCollectionInterface
{
/** @var JsonRpcResponseInterface[] */
protected $hashedResponses = [];
/** @var Response */
private $response;
/** @var RequestTransformation[] */
private $transformations;
/** @var JsonRpcResponseInterface[] */
private $responses = [];
/**
* JsonRpcResponseCollection constructor.
*
* @param Response $response
* @param RequestTransformation[] $transformations
*/
public function __construct(Response $response, array $transformations)
{
$this->response = $response;
$this->transformations = $transformations;
$this->sync();
}
/** {@inheritdoc} */
public function getIterator()
{
return new \ArrayIterator($this->responses);
}
/** {@inheritdoc} */
public function getResponse(RpcRequestInterface $request)
{
if (array_key_exists(spl_object_hash($request), $this->hashedResponses)) {
return $this->hashedResponses[spl_object_hash($request)];
}
$storedRequest = null;
foreach ($this->transformations as $transformation) {
if ($transformation->getOriginalCall() === $request) {
$storedRequest = $transformation->getTransformedCall();
break;
}
}
if (null === $storedRequest) {
throw new \OutOfBoundsException('Given request was not invoked for this collection');
}
if ($storedRequest->isNotification()) {
$this->hashedResponses[spl_object_hash($request)] = new JsonRpcNotificationResponse();
return $this->hashedResponses[spl_object_hash($request)];
}
if (!array_key_exists($storedRequest->getId(), $this->responses)) {
throw JsonRpcProtocolException::requestSendButNotResponded($storedRequest);
}
$this->hashedResponses[spl_object_hash($request)] = $this->responses[$storedRequest->getId()];
return $this->hashedResponses[spl_object_hash($request)];
}
private function sync()
{
if (200 !== $this->response->getStatus()) {
throw new RemoteCallFailedException('Remote response was not successful');
}
$data = (string)$this->response->getContent();
// Null (empty response) is expected if only notifications were sent
$rawResponses = [];
if ('' !== $data) {
$rawResponses = json_decode($data, false);
if (json_last_error() !== JSON_ERROR_NONE) {
throw ResponseParseException::notAJsonResponse();
}
}
if (!is_array($rawResponses) && $rawResponses instanceof \stdClass) {
$rawResponses = [$rawResponses];
}
$this->responses = [];
foreach ((array)$rawResponses as $rawResponse) {
try {
$response = new SyncResponse($rawResponse);
} catch (ResponseParseException $exception) {
continue;
}
$this->responses[$response->getId()] = $response;
}
}
}