Response   B
last analyzed

Complexity

Total Complexity 43

Size/Duplication

Total Lines 431
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Importance

Changes 0
Metric Value
wmc 43
lcom 1
cbo 0
dl 0
loc 431
rs 8.3157
c 0
b 0
f 0

25 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
A __toString() 0 7 1
A sendContent() 0 6 1
A sendHeaders() 0 7 2
A send() 0 11 2
A setHeaders() 0 4 1
B setContent() 0 10 5
A getContent() 0 4 1
A setProtocolVersion() 0 6 1
A getProtocolVersion() 0 4 1
B setStatusCode() 0 23 5
A getStatusCode() 0 4 1
A setCharset() 0 6 1
A getCharset() 0 4 1
A isInvalid() 0 4 2
A isInformational() 0 4 2
A isSuccessful() 0 4 2
A isRedirection() 0 4 2
A isClientError() 0 4 2
A isServerError() 0 4 2
A isOk() 0 4 1
A isForbidden() 0 4 1
A isNotFound() 0 4 1
A isRedirect() 0 4 3
A isEmpty() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like Response often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Response, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace JetFire\Routing;
4
5
6
/**
7
 * Class Response
8
 * @package JetFire\Routing
9
 */
10
class Response implements ResponseInterface{
11
12
    /**
13
     * @var array
14
     */
15
    public $headers;
16
17
    /**
18
     * @var string
19
     */
20
    protected $content;
21
22
    /**
23
     * @var string
24
     */
25
    protected $version;
26
27
    /**
28
     * @var int
29
     */
30
    protected $statusCode;
31
32
    /**
33
     * @var string
34
     */
35
    protected $statusText;
36
37
    /**
38
     * @var string
39
     */
40
    protected $charset;
41
42
    /**
43
     * Status codes translation table.
44
     *
45
     * The list of codes is complete according to the
46
     * {@link http://www.iana.org/assignments/http-status-codes/ Hypertext Transfer Protocol (HTTP) Status Code Registry}
47
     * (last updated 2015-05-19).
48
     *
49
     * Unless otherwise noted, the status code is defined in RFC2616.
50
     *
51
     * @var array
52
     */
53
    public static $statusTexts = array(
54
        100 => 'Continue',
55
        101 => 'Switching Protocols',
56
        102 => 'Processing',            // RFC2518
57
        200 => 'OK',
58
        201 => 'Created',
59
        202 => 'Accepted',
60
        203 => 'Non-Authoritative Information',
61
        204 => 'No Content',
62
        205 => 'Reset Content',
63
        206 => 'Partial Content',
64
        207 => 'Multi-Status',          // RFC4918
65
        208 => 'Already Reported',      // RFC5842
66
        226 => 'IM Used',               // RFC3229
67
        300 => 'Multiple Choices',
68
        301 => 'Moved Permanently',
69
        302 => 'Found',
70
        303 => 'See Other',
71
        304 => 'Not Modified',
72
        305 => 'Use Proxy',
73
        307 => 'Temporary Redirect',
74
        308 => 'Permanent Redirect',    // RFC7238
75
        400 => 'Bad Request',
76
        401 => 'Unauthorized',
77
        402 => 'Payment Required',
78
        403 => 'Forbidden',
79
        404 => 'Not Found',
80
        405 => 'Method Not Allowed',
81
        406 => 'Not Acceptable',
82
        407 => 'Proxy Authentication Required',
83
        408 => 'Request Timeout',
84
        409 => 'Conflict',
85
        410 => 'Gone',
86
        411 => 'Length Required',
87
        412 => 'Precondition Failed',
88
        413 => 'Payload Too Large',
89
        414 => 'URI Too Long',
90
        415 => 'Unsupported Media Type',
91
        416 => 'Range Not Satisfiable',
92
        417 => 'Expectation Failed',
93
        418 => 'I\'m a teapot',                                               // RFC2324
94
        422 => 'Unprocessable Entity',                                        // RFC4918
95
        423 => 'Locked',                                                      // RFC4918
96
        424 => 'Failed Dependency',                                           // RFC4918
97
        425 => 'Reserved for WebDAV advanced collections expired proposal',   // RFC2817
98
        426 => 'Upgrade Required',                                            // RFC2817
99
        428 => 'Precondition Required',                                       // RFC6585
100
        429 => 'Too Many Requests',                                           // RFC6585
101
        431 => 'Request Header Fields Too Large',                             // RFC6585
102
        500 => 'Internal Server Error',
103
        501 => 'Not Implemented',
104
        502 => 'Bad Gateway',
105
        503 => 'Service Unavailable',
106
        504 => 'Gateway Timeout',
107
        505 => 'HTTP Version Not Supported',
108
        506 => 'Variant Also Negotiates (Experimental)',                      // RFC2295
109
        507 => 'Insufficient Storage',                                        // RFC4918
110
        508 => 'Loop Detected',                                               // RFC5842
111
        510 => 'Not Extended',                                                // RFC2774
112
        511 => 'Network Authentication Required',                             // RFC6585
113
    );
114
115
    /**
116
     * Constructor.
117
     *
118
     * @param mixed $content The response content, see setContent()
119
     * @param int   $status  The response status code
120
     * @param array $headers An array of response headers
121
     *
122
     * @throws \InvalidArgumentException When the HTTP status code is not valid
123
     */
124
    public function __construct($content = '', $status = 200, $headers = array())
125
    {
126
        $this->headers = $headers;
127
        $this->setContent($content);
128
        $this->setStatusCode($status);
129
        $this->setProtocolVersion('1.0');
130
    }
131
132
133
    /**
134
     * Returns the Response as an HTTP string.
135
     *
136
     * The string representation of the Response is the same as the
137
     * one that will be sent to the client only if the prepare() method
138
     * has been called before.
139
     *
140
     * @return string The Response as an HTTP string
141
     *
142
     * @see prepare()
143
     */
144
    public function __toString()
145
    {
146
        return
147
            sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText)."\r\n".
148
            $this->headers."\r\n".
149
            $this->getContent();
150
    }
151
152
    /**
153
     * Sends content for the current web response.
154
     *
155
     * @return Response
156
     */
157
    public function sendContent()
158
    {
159
        echo $this->content;
160
161
        return $this;
162
    }
163
164
    /**
165
     * @return $this
166
     */
167
    public function sendHeaders()
168
    {
169
        foreach($this->headers as $key => $content)
170
            header($key.' : '.$content);
171
        http_response_code($this->getStatusCode());
172
        return $this;
173
    }
174
175
    /**
176
     * Sends HTTP headers and content.
177
     *
178
     * @return Response
179
     */
180
    public function send()
181
    {
182
        $this->sendHeaders();
183
        $this->sendContent();
184
185
        if (function_exists('fastcgi_finish_request')) {
186
            fastcgi_finish_request();
187
        }
188
189
        return $this;
190
    }
191
192
    /**
193
     * @param array $headers
194
     */
195
    public function setHeaders($headers = [])
196
    {
197
        $this->headers = $headers;
198
    }
199
    /**
200
     * Sets the response content.
201
     *
202
     * Valid types are strings, numbers, null, and objects that implement a __toString() method.
203
     *
204
     * @param mixed $content Content that can be cast to string
205
     *
206
     * @return Response
207
     *
208
     * @throws \UnexpectedValueException
209
     */
210
    public function setContent($content)
211
    {
212
        if (null !== $content && !is_string($content) && !is_numeric($content) && !is_callable(array($content, '__toString'))) {
213
            throw new \UnexpectedValueException(sprintf('The Response content must be a string or object implementing __toString(), "%s" given.', gettype($content)));
214
        }
215
216
        $this->content = (string) $content;
217
218
        return $this;
219
    }
220
221
    /**
222
     * Gets the current response content.
223
     *
224
     * @return string Content
225
     */
226
    public function getContent()
227
    {
228
        return $this->content;
229
    }
230
231
    /**
232
     * Sets the HTTP protocol version (1.0 or 1.1).
233
     *
234
     * @param string $version The HTTP protocol version
235
     *
236
     * @return Response
237
     */
238
    public function setProtocolVersion($version)
239
    {
240
        $this->version = $version;
241
242
        return $this;
243
    }
244
245
    /**
246
     * Gets the HTTP protocol version.
247
     *
248
     * @return string The HTTP protocol version
249
     */
250
    public function getProtocolVersion()
251
    {
252
        return $this->version;
253
    }
254
255
    /**
256
     * Sets the response status code.
257
     *
258
     * @param int   $code HTTP status code
259
     * @param mixed $text HTTP status text
260
     *
261
     * If the status text is null it will be automatically populated for the known
262
     * status codes and left empty otherwise.
263
     *
264
     * @return Response
265
     *
266
     * @throws \InvalidArgumentException When the HTTP status code is not valid
267
     */
268
    public function setStatusCode($code, $text = null)
269
    {
270
        $this->statusCode = $code = (int) $code;
271
        if ($this->isInvalid()) {
272
            throw new \InvalidArgumentException(sprintf('The HTTP status code "%s" is not valid.', $code));
273
        }
274
275
        if (null === $text) {
276
            $this->statusText = isset(self::$statusTexts[$code]) ? self::$statusTexts[$code] : 'unknown status';
277
278
            return $this;
279
        }
280
281
        if (false === $text) {
282
            $this->statusText = '';
283
284
            return $this;
285
        }
286
287
        $this->statusText = $text;
288
289
        return $this;
290
    }
291
292
    /**
293
     * Retrieves the status code for the current web response.
294
     *
295
     * @return int Status code
296
     */
297
    public function getStatusCode()
298
    {
299
        return $this->statusCode;
300
    }
301
302
    /**
303
     * Sets the response charset.
304
     *
305
     * @param string $charset Character set
306
     *
307
     * @return Response
308
     */
309
    public function setCharset($charset)
310
    {
311
        $this->charset = $charset;
312
313
        return $this;
314
    }
315
316
    /**
317
     * Retrieves the response charset.
318
     *
319
     * @return string Character set
320
     */
321
    public function getCharset()
322
    {
323
        return $this->charset;
324
    }
325
326
327
    // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
328
    /**
329
     * Is response invalid?
330
     *
331
     * @return bool
332
     */
333
    public function isInvalid()
334
    {
335
        return $this->statusCode < 100 || $this->statusCode >= 600;
336
    }
337
338
    /**
339
     * Is response informative?
340
     *
341
     * @return bool
342
     */
343
    public function isInformational()
344
    {
345
        return $this->statusCode >= 100 && $this->statusCode < 200;
346
    }
347
348
    /**
349
     * Is response successful?
350
     *
351
     * @return bool
352
     */
353
    public function isSuccessful()
354
    {
355
        return $this->statusCode >= 200 && $this->statusCode < 300;
356
    }
357
358
    /**
359
     * Is the response a redirect?
360
     *
361
     * @return bool
362
     */
363
    public function isRedirection()
364
    {
365
        return $this->statusCode >= 300 && $this->statusCode < 400;
366
    }
367
368
    /**
369
     * Is there a client error?
370
     *
371
     * @return bool
372
     */
373
    public function isClientError()
374
    {
375
        return $this->statusCode >= 400 && $this->statusCode < 500;
376
    }
377
378
    /**
379
     * Was there a server side error?
380
     *
381
     * @return bool
382
     */
383
    public function isServerError()
384
    {
385
        return $this->statusCode >= 500 && $this->statusCode < 600;
386
    }
387
388
    /**
389
     * Is the response OK?
390
     *
391
     * @return bool
392
     */
393
    public function isOk()
394
    {
395
        return 200 === $this->statusCode;
396
    }
397
398
    /**
399
     * Is the response forbidden?
400
     *
401
     * @return bool
402
     */
403
    public function isForbidden()
404
    {
405
        return 403 === $this->statusCode;
406
    }
407
408
    /**
409
     * Is the response a not found error?
410
     *
411
     * @return bool
412
     */
413
    public function isNotFound()
414
    {
415
        return 404 === $this->statusCode;
416
    }
417
418
    /**
419
     * Is the response a redirect of some form?
420
     *
421
     * @param string $location
422
     *
423
     * @return bool
424
     */
425
    public function isRedirect($location = null)
426
    {
427
        return in_array($this->statusCode, array(201, 301, 302, 303, 307, 308)) && (null === $location ?: $location == $this->headers->get('Location'));
0 ignored issues
show
Bug introduced by
The method get cannot be called on $this->headers (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
428
    }
429
430
    /**
431
     * Is the response empty?
432
     *
433
     * @return bool
434
     */
435
    public function isEmpty()
436
    {
437
        return in_array($this->statusCode, array(204, 304));
438
    }
439
440
}
441