Completed
Push — master ( 913926...597557 )
by Denis
02:01
created

Client::getTransport()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
3
namespace PhpJsonRpc;
4
5
use PhpJsonRpc\Client\IdGenerator;
6
use PhpJsonRpc\Client\IdGeneratorInterface;
7
use PhpJsonRpc\Core\Result\ResultError;
8
use PhpJsonRpc\Error\InvalidResponseException;
9
use PhpJsonRpc\Client\HttpTransport;
10
use PhpJsonRpc\Client\AbstractTransport;
11
use PhpJsonRpc\Client\RequestBuilder;
12
use PhpJsonRpc\Client\ResponseParser;
13
use PhpJsonRpc\Core\Call\AbstractCall;
14
use PhpJsonRpc\Core\Call\CallNotification;
15
use PhpJsonRpc\Core\Call\CallUnit;
16
use PhpJsonRpc\Core\CallSpecifier;
17
use PhpJsonRpc\Core\Result\ResultUnit;
18
use PhpJsonRpc\Core\ResultSpecifier;
19
20
class Client
21
{
22
    /**
23
     * @var AbstractCall[]
24
     */
25
    private $units = [];
26
27
    /**
28
     * @var bool
29
     */
30
    private $isSingleRequest = true;
31
32
    /**
33
     * @var RequestBuilder
34
     */
35
    private $requestBuilder;
36
37
    /**
38
     * @var AbstractTransport
39
     */
40
    private $transport;
41
42
    /**
43
     * @var ResponseParser
44
     */
45
    private $responseParser;
46
47
    /**
48
     * @var IdGeneratorInterface
49
     */
50
    private $generatorId;
51
52
    /**
53
     * Client constructor.
54
     *
55
     * @param string $url
56
     */
57
    public function __construct(string $url)
58
    {
59
        $this->requestBuilder = new RequestBuilder();
60
        $this->transport      = new HttpTransport($url);
61
        $this->responseParser = new ResponseParser();
62
        $this->generatorId    = new IdGenerator();
63
    }
64
65
    /**
66
     * @return AbstractTransport
67
     */
68
    public function getTransport(): AbstractTransport
69
    {
70
        return $this->transport;
71
    }
72
73
    /**
74
     * Set transport engine
75
     *
76
     * @param AbstractTransport $transport
77
     */
78
    public function setTransport(AbstractTransport $transport)
79
    {
80
        $this->transport = $transport;
81
    }
82
83
    /**
84
     * @return IdGeneratorInterface
85
     */
86
    public function getGeneratorId(): IdGeneratorInterface
87
    {
88
        return $this->generatorId;
89
    }
90
91
    /**
92
     * @param IdGeneratorInterface $idGenerator
93
     */
94
    public function setIdGenerator(IdGeneratorInterface $idGenerator)
95
    {
96
        $this->generatorId = $idGenerator;
97
    }
98
99
    /**
100
     * Make request
101
     *
102
     * @param string $method
103
     * @param array  $parameters
104
     *
105
     * @return $this|mixed
106
     */
107
    public function call(string $method, array $parameters)
108
    {
109
        $this->units[] = new CallUnit($this->generatorId->get(), $method, $parameters);
110
111
        if ($this->isSingleRequest) {
112
            $resultSpecifier = $this->execute(new CallSpecifier($this->units, true));
113
114
            if (!$resultSpecifier->isSingleResult()) {
115
                throw new InvalidResponseException();
116
            }
117
118
            list($result) = $resultSpecifier->getResults();
119
120
            if ($result instanceof ResultUnit) {
121
                /** @var ResultUnit $result */
122
                return $result->getResult();
123
            }
124
125
            return null;
126
        }
127
128
        return $this;
129
    }
130
131
    /**
132
     * Make notification request
133
     *
134
     * @param string $method
135
     * @param array  $parameters
136
     *
137
     * @return $this|null
138
     */
139
    public function notification(string $method, array $parameters)
140
    {
141
        $this->units[] = new CallNotification($method, $parameters);
142
143
        if ($this->isSingleRequest) {
144
            $this->execute(new CallSpecifier($this->units, true));
145
            return null;
146
        }
147
148
        return $this;
149
    }
150
151
    /**
152
     * Start batch request
153
     *
154
     * @return $this
155
     */
156
    public function batch()
157
    {
158
        $this->isSingleRequest = false;
159
        return $this;
160
    }
161
162
    /**
163
     * Execute batch request
164
     *
165
     * @return array
166
     */
167
    public function batchExecute()
168
    {
169
        $results = $this->execute(new CallSpecifier($this->units, false))->getResults();
170
171
        // Make right order in sequence of results. It's required operation, because JSON-RPC2
172
        // specification define: "The Response objects being returned from a batch call MAY be returned
173
        // in any order within the Array. The Client SHOULD match contexts between the set of Request objects and the
174
        // resulting set of Response objects based on the id member within each Object."
175
176
        $callMap = [];
177
        foreach ($this->units as $index => $unit) {
178
            /** @var CallUnit $unit */
179
            $callMap[$unit->getRawId()] = $index;
180
        }
181
182
        if (count($results) !== count($this->units)) {
183
            throw new InvalidResponseException();
184
        }
185
186
        $resultSequence = [];
187
        foreach ($results as $result) {
188
            if ($result instanceof ResultUnit) {
189
                /** @var ResultUnit $result */
190
                $resultSequence[ $callMap[$result->getId()] ] = $result->getResult();
191
            } elseif ($result instanceof ResultError) {
192
                /** @var ResultError $result */
193
                $resultSequence[ $callMap[$result->getId()] ] = null;
194
            }
195
        }
196
        ksort($resultSequence);
197
198
        return $resultSequence;
199
    }
200
201
    /**
202
     * @param CallSpecifier $call
203
     *
204
     * @return ResultSpecifier
205
     */
206
    private function execute(CallSpecifier $call): ResultSpecifier
207
    {
208
        $request  = $this->requestBuilder->build($call);
209
        $response = $this->transport->request($request);
210
211
        return $this->responseParser->parse($response);
212
    }
213
}
214