Completed
Push — master ( 841bb5...43701d )
by Nate
09:20
created

Response::createContext()   D

Complexity

Conditions 9
Paths 64

Size

Total Lines 35
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 35
rs 4.909
cc 9
eloc 18
nc 64
nop 0
1
<?php
2
/*
3
 * Copyright (c) Nate Brunette.
4
 * Distributed under the MIT License (http://opensource.org/licenses/MIT)
5
 */
6
7
namespace Tebru\Retrofit\Http;
8
9
use JMS\Serializer\DeserializationContext;
10
use JMS\Serializer\SerializerInterface;
11
use Psr\Http\Message\ResponseInterface;
12
use Psr\Http\Message\StreamInterface;
13
14
/**
15
 * Class Response
16
 *
17
 * @author Nate Brunette <[email protected]>
18
 */
19
class Response implements ResponseInterface
20
{
21
    const FORMAT_RAW = 'raw';
22
    const FORMAT_ARRAY = 'array';
23
24
    /**
25
     * PSR-7 Response
26
     *
27
     * @var ResponseInterface
28
     */
29
    private $response;
30
31
    /**
32
     * The return type
33
     *
34
     * @var string
35
     */
36
    private $returnType;
37
38
    /**
39
     * JMS Serializer
40
     *
41
     * @var SerializerInterface
42
     */
43
    private $serializer;
44
45
    /**
46
     * Serialization context
47
     *
48
     * @var array
49
     */
50
    private $context;
51
52
    /**
53
     * Constructor
54
     *
55
     * @param ResponseInterface $response
56
     * @param string $returnType
57
     * @param SerializerInterface $serializer
58
     * @param array $context
59
     */
60
    public function __construct(
61
        ResponseInterface $response,
62
        $returnType,
63
        SerializerInterface $serializer,
64
        array $context = []
65
    ) {
66
        $this->response = $response;
67
        $this->returnType = $returnType;
68
        $this->serializer = $serializer;
69
        $this->context = $context;
70
    }
71
72
    /**
73
     * Get the body specified by the Returns annotation
74
     *
75
     * @return mixed
76
     */
77
    public function body()
78
    {
79
        $responseBody = (string) $this->response->getBody();
80
        switch ($this->returnType) {
81
            case self::FORMAT_RAW:
82
                $response = $responseBody;
83
                break;
84
            case self::FORMAT_ARRAY:
85
                $response = json_decode($responseBody, true);
86
                break;
87
            default:
88
                $context = $this->createContext();
89
                $response = $this->serializer->deserialize($responseBody, $this->returnType, 'json', $context);
90
        }
91
92
        return $response;
93
    }
94
95
    /**
96
     * Build the deserialization context
97
     */
98
    private function createContext()
99
    {
100
        $context = new DeserializationContext();
101
102
        if (!empty($this->context['groups'])) {
103
            $context->setGroups($this->context['groups']);
104
        }
105
106
        if (!empty($this->context['version'])) {
107
            $context->setVersion((int) $this->context['version']);
108
        }
109
110
        if (!empty($this->context['serializeNull'])) {
111
            $context->setSerializeNull((bool) $this->context['serializeNull']);
112
        }
113
114
        if (!empty($this->context['enableMaxDepthChecks'])) {
115
            $context->enableMaxDepthChecks();
116
        }
117
118
        if (!empty($this->context['attributes'])) {
119
            foreach ($this->context['attributes'] as $key => $value) {
120
                $context->setAttribute($key, $value);
121
            }
122
        }
123
124
        if (!empty($this->context['depth'])) {
125
            $contextDepth = (int) $this->context['depth'];
126
            while ($context->getDepth() < $contextDepth) {
127
                $context->increaseDepth();
128
            }
129
        }
130
131
        return $context;
132
    }
133
134
    /**
135
     * Retrieves the HTTP protocol version as a string.
136
     *
137
     * The string MUST contain only the HTTP version number (e.g., "1.1", "1.0").
138
     *
139
     * @return string HTTP protocol version.
140
     */
141
    public function getProtocolVersion()
142
    {
143
        return $this->response->getProtocolVersion();
144
    }
145
146
    /**
147
     * Return an instance with the specified HTTP protocol version.
148
     *
149
     * The version string MUST contain only the HTTP version number (e.g.,
150
     * "1.1", "1.0").
151
     *
152
     * This method MUST be implemented in such a way as to retain the
153
     * immutability of the message, and MUST return an instance that has the
154
     * new protocol version.
155
     *
156
     * @param string $version HTTP protocol version
157
     * @return self
158
     */
159
    public function withProtocolVersion($version)
160
    {
161
        return $this->response->withProtocolVersion($version);
162
    }
163
164
    /**
165
     * Retrieves all message header values.
166
     *
167
     * The keys represent the header name as it will be sent over the wire, and
168
     * each value is an array of strings associated with the header.
169
     *
170
     *     // Represent the headers as a string
171
     *     foreach ($message->getHeaders() as $name => $values) {
172
     *         echo $name . ": " . implode(", ", $values);
173
     *     }
174
     *
175
     *     // Emit headers iteratively:
176
     *     foreach ($message->getHeaders() as $name => $values) {
177
     *         foreach ($values as $value) {
178
     *             header(sprintf('%s: %s', $name, $value), false);
179
     *         }
180
     *     }
181
     *
182
     * While header names are not case-sensitive, getHeaders() will preserve the
183
     * exact case in which headers were originally specified.
184
     *
185
     * @return array Returns an associative array of the message's headers. Each
186
     *     key MUST be a header name, and each value MUST be an array of strings
187
     *     for that header.
188
     */
189
    public function getHeaders()
190
    {
191
        return $this->response->getHeaders();
192
    }
193
194
    /**
195
     * Checks if a header exists by the given case-insensitive name.
196
     *
197
     * @param string $name Case-insensitive header field name.
198
     * @return bool Returns true if any header names match the given header
199
     *     name using a case-insensitive string comparison. Returns false if
200
     *     no matching header name is found in the message.
201
     */
202
    public function hasHeader($name)
203
    {
204
        return $this->response->hasHeader($name);
205
    }
206
207
    /**
208
     * Retrieves a message header value by the given case-insensitive name.
209
     *
210
     * This method returns an array of all the header values of the given
211
     * case-insensitive header name.
212
     *
213
     * If the header does not appear in the message, this method MUST return an
214
     * empty array.
215
     *
216
     * @param string $name Case-insensitive header field name.
217
     * @return string[] An array of string values as provided for the given
218
     *    header. If the header does not appear in the message, this method MUST
219
     *    return an empty array.
220
     */
221
    public function getHeader($name)
222
    {
223
        return $this->response->getHeader($name);
224
    }
225
226
    /**
227
     * Retrieves a comma-separated string of the values for a single header.
228
     *
229
     * This method returns all of the header values of the given
230
     * case-insensitive header name as a string concatenated together using
231
     * a comma.
232
     *
233
     * NOTE: Not all header values may be appropriately represented using
234
     * comma concatenation. For such headers, use getHeader() instead
235
     * and supply your own delimiter when concatenating.
236
     *
237
     * If the header does not appear in the message, this method MUST return
238
     * an empty string.
239
     *
240
     * @param string $name Case-insensitive header field name.
241
     * @return string A string of values as provided for the given header
242
     *    concatenated together using a comma. If the header does not appear in
243
     *    the message, this method MUST return an empty string.
244
     */
245
    public function getHeaderLine($name)
246
    {
247
        return $this->response->getHeaderLine($name);
248
    }
249
250
    /**
251
     * Return an instance with the provided value replacing the specified header.
252
     *
253
     * While header names are case-insensitive, the casing of the header will
254
     * be preserved by this function, and returned from getHeaders().
255
     *
256
     * This method MUST be implemented in such a way as to retain the
257
     * immutability of the message, and MUST return an instance that has the
258
     * new and/or updated header and value.
259
     *
260
     * @param string $name Case-insensitive header field name.
261
     * @param string|string[] $value Header value(s).
262
     * @return self
263
     * @throws \InvalidArgumentException for invalid header names or values.
264
     */
265
    public function withHeader($name, $value)
266
    {
267
        return $this->response->withHeader($name, $value);
268
    }
269
270
    /**
271
     * Return an instance with the specified header appended with the given value.
272
     *
273
     * Existing values for the specified header will be maintained. The new
274
     * value(s) will be appended to the existing list. If the header did not
275
     * exist previously, it will be added.
276
     *
277
     * This method MUST be implemented in such a way as to retain the
278
     * immutability of the message, and MUST return an instance that has the
279
     * new header and/or value.
280
     *
281
     * @param string $name Case-insensitive header field name to add.
282
     * @param string|string[] $value Header value(s).
283
     * @return self
284
     * @throws \InvalidArgumentException for invalid header names or values.
285
     */
286
    public function withAddedHeader($name, $value)
287
    {
288
        return $this->response->withAddedHeader($name, $value);
289
    }
290
291
    /**
292
     * Return an instance without the specified header.
293
     *
294
     * Header resolution MUST be done without case-sensitivity.
295
     *
296
     * This method MUST be implemented in such a way as to retain the
297
     * immutability of the message, and MUST return an instance that removes
298
     * the named header.
299
     *
300
     * @param string $name Case-insensitive header field name to remove.
301
     * @return self
302
     */
303
    public function withoutHeader($name)
304
    {
305
        return $this->response->withoutHeader($name);
306
    }
307
308
    /**
309
     * Gets the body of the message.
310
     *
311
     * @return StreamInterface Returns the body as a stream.
312
     */
313
    public function getBody()
314
    {
315
        return $this->response->getBody();
316
    }
317
318
    /**
319
     * Return an instance with the specified message body.
320
     *
321
     * The body MUST be a StreamInterface object.
322
     *
323
     * This method MUST be implemented in such a way as to retain the
324
     * immutability of the message, and MUST return a new instance that has the
325
     * new body stream.
326
     *
327
     * @param StreamInterface $body Body.
328
     * @return self
329
     * @throws \InvalidArgumentException When the body is not valid.
330
     */
331
    public function withBody(StreamInterface $body)
332
    {
333
        return $this->response->withBody($body);
334
    }
335
336
    /**
337
     * Gets the response status code.
338
     *
339
     * The status code is a 3-digit integer result code of the server's attempt
340
     * to understand and satisfy the request.
341
     *
342
     * @return int Status code.
343
     */
344
    public function getStatusCode()
345
    {
346
        return $this->response->getStatusCode();
347
    }
348
349
    /**
350
     * Return an instance with the specified status code and, optionally, reason phrase.
351
     *
352
     * If no reason phrase is specified, implementations MAY choose to default
353
     * to the RFC 7231 or IANA recommended reason phrase for the response's
354
     * status code.
355
     *
356
     * This method MUST be implemented in such a way as to retain the
357
     * immutability of the message, and MUST return an instance that has the
358
     * updated status and reason phrase.
359
     *
360
     * @link http://tools.ietf.org/html/rfc7231#section-6
361
     * @link http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
362
     * @param int $code The 3-digit integer result code to set.
363
     * @param string $reasonPhrase The reason phrase to use with the
364
     *     provided status code; if none is provided, implementations MAY
365
     *     use the defaults as suggested in the HTTP specification.
366
     * @return self
367
     * @throws \InvalidArgumentException For invalid status code arguments.
368
     */
369
    public function withStatus($code, $reasonPhrase = '')
370
    {
371
        return $this->response->withStatus($code, $reasonPhrase);
372
    }
373
374
    /**
375
     * Gets the response reason phrase associated with the status code.
376
     *
377
     * Because a reason phrase is not a required element in a response
378
     * status line, the reason phrase value MAY be null. Implementations MAY
379
     * choose to return the default RFC 7231 recommended reason phrase (or those
380
     * listed in the IANA HTTP Status Code Registry) for the response's
381
     * status code.
382
     *
383
     * @link http://tools.ietf.org/html/rfc7231#section-6
384
     * @link http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
385
     * @return string Reason phrase; must return an empty string if none present.
386
     */
387
    public function getReasonPhrase()
388
    {
389
        return $this->response->getReasonPhrase();
390
    }
391
}
392