Passed
Push — master ( 4ac306...d2aa89 )
by Mihail
05:30
created

ServerResponse::getContentType()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 1
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 2
rs 10
1
<?php
2
3
/*
4
 * This file is part of the Koded package.
5
 *
6
 * (c) Mihail Binev <[email protected]>
7
 *
8
 * Please view the LICENSE distributed with this source code
9
 * for the full copyright and license information.
10
 *
11
 */
12
13
namespace Koded\Http;
14
15
use InvalidArgumentException;
16
use JsonSerializable;
17
use Koded\Http\Interfaces\{HttpStatus, Request, Response};
18
19
/**
20
 * Class ServerResponse
21
 *
22
 */
23
class ServerResponse implements Response, JsonSerializable
24
{
25
    use HeaderTrait, MessageTrait, CookieTrait, JsonSerializeTrait;
26
27
    private const E_CLIENT_RESPONSE_SEND = 'Cannot send the client response.';
28
    private const E_INVALID_STATUS_CODE  = 'Invalid status code %s, expected range between [100-599]';
29
30
    protected $statusCode   = HttpStatus::OK;
31
    protected $reasonPhrase = 'OK';
32
33
    /**
34
     * ServerResponse constructor.
35
     *
36
     * @param mixed $content    [optional]
37
     * @param int   $statusCode [optional]
38
     * @param array $headers    [optional]
39
     */
40 51
    public function __construct($content = '', int $statusCode = HttpStatus::OK, array $headers = [])
41
    {
42 51
        $this->setStatus($this, $statusCode);
43 51
        $this->setHeaders($headers);
44 51
        $this->stream = create_stream($content);
45 51
    }
46
47 33
    public function getStatusCode(): int
48
    {
49 33
        return $this->statusCode;
50
    }
51
52 6
    public function withStatus($code, $reasonPhrase = ''): Response
53
    {
54 6
        return $this->setStatus(clone $this, (int)$code, (string)$reasonPhrase);
55
    }
56
57 9
    public function getReasonPhrase(): string
58
    {
59 9
        return (string)$this->reasonPhrase;
60
    }
61
62 2
    public function getContentType(): string
63
    {
64 2
        return $this->getHeaderLine('Content-Type') ?: 'text/html';
65
    }
66
67 4
    public function send(): string
68
    {
69 4
        $this->prepareResponse();
70
71 4
        if (headers_sent()) {
72 1
            return (string)$this->stream;
73
        }
74
75
        // Headers
76 3
        foreach ($this->getHeaders() as $name => $values) {
77 2
            header($name . ':' . join(',', (array)$values), false, $this->statusCode);
0 ignored issues
show
Unused Code introduced by
The call to Koded\Http\header() has too many arguments starting with $name . ':' . join(',', (array)$values). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

77
            /** @scrutinizer ignore-call */ 
78
            header($name . ':' . join(',', (array)$values), false, $this->statusCode);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
78
        }
79
80
        // Status header
81 3
        header(sprintf('HTTP/%s %d %s', $this->getProtocolVersion(), $this->getStatusCode(), $this->getReasonPhrase()),
82 3
            true, $this->statusCode
83
        );
84
85 3
        return (string)$this->stream;
86
    }
87
88 51
    protected function setStatus(ServerResponse $instance, int $statusCode, string $reasonPhrase = ''): ServerResponse
89
    {
90 51
        if ($statusCode < 100 || $statusCode > 599) {
91 1
            throw new InvalidArgumentException(
92 1
                sprintf(self::E_INVALID_STATUS_CODE, $statusCode), HttpStatus::UNPROCESSABLE_ENTITY
93
            );
94
        }
95
96 51
        $instance->statusCode   = (int)$statusCode;
97 51
        $instance->reasonPhrase = $reasonPhrase ? (string)$reasonPhrase : StatusCode::CODE[$statusCode];
98
99 51
        return $instance;
100
    }
101
102 4
    protected function prepareResponse(): void
103
    {
104 4
        if (in_array($this->getStatusCode(), [100, 101, 102, 204, 304])) {
105 1
            $this->stream = create_stream(null);
106 1
            unset($this->headersMap['content-length'], $this->headers['Content-Length']);
107 1
            unset($this->headersMap['content-type'], $this->headers['Content-Type']);
108
109 1
            return;
110
        }
111
112 3
        if ($size = $this->stream->getSize()) {
113 3
            $this->normalizeHeader('Content-Length', $size, true);
114
        }
115
116 3
        if (Request::HEAD === strtoupper($_SERVER['REQUEST_METHOD'] ?? '')) {
117 2
            $this->stream = create_stream(null);
118
        }
119
120 3
        if ($this->hasHeader('Transfer-Encoding') || !$size) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $size of type integer|null is loosely compared to false; this is ambiguous if the integer can be 0. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
121 1
            unset($this->headersMap['content-length'], $this->headers['Content-Length']);
122
        }
123 3
    }
124
}
125