Completed
Push — master ( 369b2c...ffb215 )
by Anton
8s
created

Response::getReasonPhrase()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
/**
3
 * Bluz Framework Component
4
 *
5
 * @copyright Bluz PHP Team
6
 * @link https://github.com/bluzphp/framework
7
 */
8
9
/**
10
 * @namespace
11
 */
12
namespace Bluz\Response;
13
14
use Bluz\Common\Options;
15
use Bluz\Proxy\Messages;
16
use Bluz\View\View;
17
use Zend\Diactoros\Response\EmptyResponse;
18
use Zend\Diactoros\Response\HtmlResponse;
19
use Zend\Diactoros\Response\JsonResponse;
20
use Zend\Diactoros\Response\RedirectResponse;
21
use Zend\Diactoros\Response\SapiEmitter;
22
23
/**
24
 * Response Container
25
 *
26
 * @package  Bluz\Response
27
 * @author   Anton Shevchuk
28
 * @link     https://github.com/bluzphp/framework/wiki/Response
29
 */
30
class Response
31
{
32
    use Options;
33
34
    /**
35
     * @var string HTTP protocol version
36
     */
37
    protected $protocol = '1.1';
38
39
    /**
40
     * @var integer response code equal to HTTP status codes
41
     */
42
    protected $code = 200;
43
44
    /**
45
     * @var string|null HTTP Phrase
46
     */
47
    protected $phrase;
48
49
    /**
50
     * @var array list of headers
51
     */
52
    protected $headers = array();
53
54
    /**
55
     * @var array list of cookies
56
     */
57
    protected $cookies = array();
58
59
    /**
60
     * @var mixed result can be View|object|function
61
     */
62
    protected $body;
63
64
    /**
65
     * send
66
     *
67
     * @return void
68
     */
69
    public function send()
70
    {
71
        // switch statement for $this->status
0 ignored issues
show
Unused Code Comprehensibility introduced by
40% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
72
        switch ($this->getStatusCode()) {
73
            case 204:
74
                $response = new EmptyResponse($this->getStatusCode(), $this->getHeaders());
75
                break;
76
            case 301:
77
            case 302:
78
                $response = new RedirectResponse(
79
                    $this->getHeader('Location'),
80
                    $this->getStatusCode(),
81
                    $this->getHeaders()
82
                );
83
                break;
84
            default:
85
                $body = $this->getBody();
86
87
                // run callable structure, but don't run view
88
                if (is_callable($body) && !($body instanceof View)) {
89
                    $body = $body();
90
                }
91
92
                if (is_null($body)) {
93
                    // empty response
94
                    $response = new EmptyResponse(
95
                        $this->getStatusCode(),
96
                        $this->getHeaders()
97
                    );
98
                } elseif (PHP_SAPI === 'cli') {
99
                    // CLI response
100
                    // extract data from view
101
                    if ($body instanceof View) {
102
                        // just print to console as key-value pair
103
                        $data = $body->toArray();
104
                        $output = array();
105
                        array_walk_recursive($data, function ($value, $key) use (&$output) {
106
                            $output[] = $key .': '. $value;
107
                        });
108
                        $body = join("\n", $output);
109
                    }
110
111
                    // @TODO: create CLIResponse
112
                    $response = new HtmlResponse(
113
                        (string) $body,
114
                        $this->getStatusCode(),
115
                        $this->getHeaders()
116
                    );
117
                } elseif ($this->getHeader('Content-Type') == 'application/json') {
118
                    // JSON response
119
120
                    // setup messages
121
                    if (Messages::count()) {
122
                        $this->setHeader('Bluz-Notify', json_encode(Messages::popAll()));
123
                    }
124
125
                    // extract data from view
126
                    if ($body instanceof View) {
127
                        $body = $body->toArray();
128
                    }
129
130
                    // encode body data to JSON
131
                    $response = new JsonResponse(
132
                        $body,
133
                        $this->getStatusCode(),
134
                        $this->getHeaders()
135
                    );
136
                } else {
137
                    // HTML response
138
                    $response = new HtmlResponse(
139
                        (string) $body,
140
                        $this->getStatusCode(),
141
                        $this->getHeaders()
142
                    );
143
                }
144
                break;
145
        }
146
147
        $emitter = new SapiEmitter();
148
        $emitter->emit($response);
149
    }
150
151
    /**
152
     * Gets the HTTP protocol version as a string
153
     *
154
     * The string MUST contain only the HTTP version number (e.g., "1.1", "1.0").
155
     *
156
     * @return string HTTP protocol version.
157
     */
158 1
    public function getProtocolVersion()
159
    {
160 1
        return $this->protocol;
161
    }
162
163
    /**
164
     * Gets the response Status-Code
165
     *
166
     * The Status-Code is a 3-digit integer result code of the server's attempt
167
     * to understand and satisfy the request.
168
     *
169
     * @return integer status code.
170
     */
171 1
    public function getStatusCode()
172
    {
173 1
        return $this->code;
174
    }
175
176
    /**
177
     * Sets the status code of this response
178
     *
179
     * @param  integer $code the 3-digit integer result code to set.
180
     * @return void
181
     */
182 11
    public function setStatusCode($code)
183
    {
184 11
        $this->code = (int) $code;
185 11
    }
186
187
    /**
188
     * Gets the response Reason-Phrase, a short textual description of the Status-Code
189
     *
190
     * Because a Reason-Phrase is not a required element in response
191
     * Status-Line, the Reason-Phrase value MAY be null. Implementations MAY
192
     * choose to return the default RFC 2616 recommended reason phrase for the
193
     * response's Status-Code.
194
     *
195
     * @return string|null reason phrase, or null if unknown.
196
     */
197 2
    public function getReasonPhrase()
198
    {
199 2
        return $this->phrase;
200
    }
201
202
    /**
203
     * Sets the Reason-Phrase of the response
204
     *
205
     * If no Reason-Phrase is specified, implementations MAY choose to default
206
     * to the RFC 2616 recommended reason phrase for the response's Status-Code.
207
     *
208
     * @param string $phrase the Reason-Phrase to set.
209
     */
210 1
    public function setReasonPhrase($phrase)
211
    {
212 1
        $this->phrase = $phrase;
213 1
    }
214
215
    /**
216
     * Retrieve a header by the given case-insensitive name as a string
217
     *
218
     * This method returns all of the header values of the given
219
     * case-insensitive header name as a string concatenated together using
220
     * a comma.
221
     *
222
     * @param  string $header case-insensitive header name.
223
     * @return string
224
     */
225 4
    public function getHeader($header)
226
    {
227 4
        if ($this->hasHeader($header)) {
228 4
            return join(', ', $this->headers[$header]);
229
        } else {
230 1
            return '';
231
        }
232
    }
233
234
    /**
235
     * Retrieves a header by the given case-insensitive name as an array of strings
236
     *
237
     * @param  string $header Case-insensitive header name.
238
     * @return string[]
239
     */
240 1
    public function getHeaderAsArray($header)
241
    {
242 1
        if ($this->hasHeader($header)) {
243 1
            return $this->headers[$header];
244
        } else {
245 1
            return array();
246
        }
247
    }
248
249
    /**
250
     * Checks if a header exists by the given case-insensitive name
251
     *
252
     * @param  string $header case-insensitive header name.
253
     * @return bool returns true if any header names match the given header
254
     *              name using a case-insensitive string comparison. Returns false if
255
     *              no matching header name is found in the message.
256
     */
257 3
    public function hasHeader($header)
258
    {
259 3
        return isset($this->headers[$header]);
260
    }
261
262
    /**
263
     * Sets a header, replacing any existing values of any headers with the
264
     * same case-insensitive name
265
     *
266
     * The header name is case-insensitive. The header values MUST be a string
267
     * or an array of strings.
268
     *
269
     * @param  string          $header header name
270
     * @param  string|string[] $value  header value(s)
271
     * @return void
272
     */
273 8
    public function setHeader($header, $value)
274
    {
275 8
        $this->headers[$header] = (array) $value;
276 8
    }
277
278
    /**
279
     * Appends a header value for the specified header
280
     *
281
     * Existing values for the specified header will be maintained. The new
282
     * value will be appended to the existing list.
283
     *
284
     * @param  string $header header name to add
285
     * @param  string $value  value of the header
286
     * @return void
287
     */
288 1
    public function addHeader($header, $value)
289
    {
290 1
        if ($this->hasHeader($header)) {
291 1
            $this->headers[$header][] = $value;
292
        } else {
293 1
            $this->setHeader($header, $value);
294
        }
295 1
    }
296
297
    /**
298
     * Remove a specific header by case-insensitive name.
299
     *
300
     * @param  string $header HTTP header to remove
301
     * @return void
302
     */
303 1
    public function removeHeader($header)
304
    {
305 1
        unset($this->headers[$header]);
306 1
    }
307
308
    /**
309
     * Gets all message headers
310
     *
311
     * The keys represent the header name as it will be sent over the wire, and
312
     * each value is an array of strings associated with the header.
313
     *
314
     *     // Represent the headers as a string
315
     *     foreach ($message->getHeaders() as $name => $values) {
316
     *         echo $name . ": " . implode(", ", $values);
317
     *     }
318
     *
319
     * @return array returns an associative array of the message's headers.
320
     */
321 1
    public function getHeaders()
322
    {
323 1
        return $this->headers;
324
    }
325
326
    /**
327
     * Sets headers, replacing any headers that have already been set on the message
328
     *
329
     * The array keys MUST be a string. The array values must be either a
330
     * string or an array of strings.
331
     *
332
     * @param  array $headers Headers to set.
333
     * @return void
334
     */
335 1
    public function setHeaders(array $headers)
336
    {
337 1
        $this->headers = $headers;
338 1
    }
339
340
    /**
341
     * Merges in an associative array of headers.
342
     *
343
     * Each array key MUST be a string representing the case-insensitive name
344
     * of a header. Each value MUST be either a string or an array of strings.
345
     * For each value, the value is appended to any existing header of the same
346
     * name, or, if a header does not already exist by the given name, then the
347
     * header is added.
348
     *
349
     * @param  array $headers Associative array of headers to add to the message
350
     * @return void
351
     */
352 1
    public function addHeaders(array $headers)
353
    {
354 1
        $this->headers = array_merge_recursive($this->headers, $headers);
355 1
    }
356
357
    /**
358
     * Remove all headers
359
     *
360
     * @return void
361
     */
362 2
    public function removeHeaders()
363
    {
364 2
        $this->headers = array();
365 2
    }
366
367
    /**
368
     * Set response body
369
     *
370
     * @param  mixed $body
371
     * @return void
372
     */
373 2
    public function setBody($body)
374
    {
375 2
        $this->body = $body;
376 2
    }
377
378
    /**
379
     * Get response body
380
     *
381
     * @return View
382
     */
383
    public function getBody()
384
    {
385
        return $this->body;
386
    }
387
388
    /**
389
     * Clear response body
390
     *
391
     * @return void
392
     */
393 1
    public function clearBody()
394
    {
395 1
        $this->body = null;
396 1
    }
397
398
    /**
399
     * Set Cookie
400
     *
401
     * @param  string               $name
402
     * @param  string               $value
403
     * @param  int|string|\DateTime $expire
404
     * @param  string               $path
405
     * @param  string               $domain
406
     * @param  bool                 $secure
407
     * @param  bool                 $httpOnly
408
     * @return void
409
     */
410 5
    public function setCookie(
411
        $name,
412
        $value = null,
413
        $expire = 0,
414
        $path = '/',
415
        $domain = null,
416
        $secure = false,
417
        $httpOnly = true
418
    ) {
419
        // from PHP source code
420 5
        if (preg_match("/[=,; \t\r\n\013\014]/", $name)) {
421 1
            throw new \InvalidArgumentException('The cookie name contains invalid characters.');
422
        }
423
424 4
        if (empty($name)) {
425 1
            throw new \InvalidArgumentException('The cookie name cannot be empty.');
426
        }
427
428
        // convert expiration time to a Unix timestamp
429 3
        if ($expire instanceof \DateTime) {
430 1
            $expire = $expire->format('U');
431 2
        } elseif (!is_numeric($expire)) {
432 1
            $expire = strtotime($expire);
433 1
            if (false === $expire || -1 === $expire) {
434 1
                throw new \InvalidArgumentException('The cookie expiration time is not valid.');
435
            }
436
        }
437
438 2
        $this->cookies[$name] = [
439 2
            'name' => $name,
440 2
            'value' => $value,
441 2
            'expire' => $expire,
442 2
            'path' => empty($path) ? '/' : $path,
443 2
            'domain' => $domain,
444 2
            'secure' => (bool) $secure,
445 2
            'httpOnly' => (bool) $httpOnly
446
        ];
447 2
    }
448
449
    /**
450
     * Get Cookie by name
451
     *
452
     * @param  string $name
453
     * @return array|null
454
     */
455 2
    public function getCookie($name)
456
    {
457 2
        return isset($this->cookies[$name])?$this->cookies[$name]:null;
458
    }
459
}
460