Passed
Push — main ( d5489c...9b3055 )
by Thomas
02:40
created

ResponseFactory::createStream()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 3
c 0
b 0
f 0
dl 0
loc 6
ccs 4
cts 4
cp 1
rs 10
cc 1
nc 1
nop 1
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Conia\Chuck;
6
7
use Conia\Chuck\Exception\HttpNotFound;
8
use Conia\Chuck\Exception\RuntimeException;
9
use Conia\Chuck\Psr\Factory;
10
use Conia\Chuck\Response;
11
use finfo;
12
use Psr\Http\Message\ResponseInterface as PsrResponse;
13
use Psr\Http\Message\StreamInterface as PsrStream;
14
use Traversable;
15
16
class ResponseFactory
17
{
18 60
    public function __construct(protected Factory $factory)
19
    {
20 60
    }
21
22
    /**
23
     * @param null|PsrStream|resource|string $body
24
     */
25 10
    public function create(
26
        int $code = 200,
27
        string $reasonPhrase = '',
28
    ): Response {
29 10
        return new Response($this->createPsrResponse($code, $reasonPhrase), $this->factory);
30
    }
31
32
    /**
33
     * @param null|PsrStream|resource|string $body
34
     */
35 18
    public function html(
36
        mixed $body = null,
37
        int $code = 200,
38
        string $reasonPhrase = '',
39
    ): Response {
40 18
        $psrResponse = $this->createPsrResponse($code, $reasonPhrase)->withAddedHeader(
41 18
            'Content-Type',
42 18
            'text/html'
43 18
        );
44
45 18
        if ($body) {
46 18
            $psrResponse = $psrResponse->withBody($this->createStream($body));
47
        }
48
49 17
        return new Response($psrResponse, $this->factory);
50
    }
51
52
    /**
53
     * @param null|PsrStream|resource|string $body
54
     */
55 13
    public function text(
56
        mixed $body = null,
57
        int $code = 200,
58
        string $reasonPhrase = '',
59
    ): Response {
60 13
        $psrResponse = $this->createPsrResponse($code, $reasonPhrase)->withAddedHeader(
61 13
            'Content-Type',
62 13
            'text/plain'
63 13
        );
64
65 13
        if ($body) {
66 12
            $psrResponse = $psrResponse->withBody($this->createStream($body));
67
        }
68
69 13
        return new Response($psrResponse, $this->factory);
70
    }
71
72 7
    public function json(
73
        mixed $data,
74
        int $code = 200,
75
        string $reasonPhrase = '',
76
        int $flags = JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR,
77
    ): Response {
78 7
        $psrResponse = $this->createPsrResponse($code, $reasonPhrase)->withAddedHeader(
79 7
            'Content-Type',
80 7
            'application/json'
81 7
        );
82
83 7
        if ($data instanceof Traversable) {
84 1
            $data = json_encode(iterator_to_array($data), $flags);
85
        } else {
86 6
            $data = json_encode($data, $flags);
87
        }
88
89 7
        $psrResponse = $psrResponse->withBody($this->createStream($data));
90
91 7
        return new Response($psrResponse, $this->factory);
92
    }
93
94 6
    public function file(
95
        string $file,
96
        bool $throwNotFound = true,
97
        int $code = 200,
98
        string $reasonPhrase = '',
99
    ): Response {
100 6
        $this->validateFile($file, $throwNotFound);
101
102 4
        $finfo = new finfo(FILEINFO_MIME_TYPE);
103 4
        $contentType = $finfo->file($file);
104 4
        $finfo = new finfo(FILEINFO_MIME_ENCODING);
105 4
        $encoding = $finfo->file($file);
106
107 4
        $psrResponse = $this->createPsrResponse($code, $reasonPhrase)
108 4
            ->withAddedHeader('Content-Type', $contentType)
109 4
            ->withAddedHeader('Content-Transfer-Encoding', $encoding);
110
111 4
        $stream = $this->factory->streamFromFile($file, 'rb');
112 4
        $size = $stream->getSize();
113
114 4
        if (!is_null($size)) {
115 4
            $psrResponse = $psrResponse->withAddedHeader('Content-Length', (string)$size);
116
        }
117
118 4
        return new Response($psrResponse->withBody($stream), $this->factory);
119
    }
120
121 3
    public function download(
122
        string $file,
123
        string $newName = '',
124
        bool $throwNotFound = true,
125
        int $code = 200,
126
        string $reasonPhrase = '',
127
    ): Response {
128 3
        $response = $this->file($file, $throwNotFound, $code, $reasonPhrase);
129 3
        $response->header(
130 3
            'Content-Disposition',
131 3
            'attachment; filename="' . ($newName ?: basename($file)) . '"'
132 3
        );
133
134 3
        return $response;
135
    }
136
137 1
    public function sendfile(
138
        string $file,
139
        bool $throwNotFound = true,
140
        int $code = 200,
141
        string $reasonPhrase = '',
142
    ): Response {
143 1
        $this->validateFile($file, $throwNotFound);
144 1
        $server = strtolower($_SERVER['SERVER_SOFTWARE'] ?? '');
145 1
        $psrResponse = $this->createPsrResponse($code, $reasonPhrase);
146
147 1
        if (strpos($server, 'nginx') !== false) {
148 1
            $psrResponse = $psrResponse->withAddedHeader('X-Accel-Redirect', $file);
149
        } else {
150 1
            $psrResponse = $psrResponse->withAddedHeader('X-Sendfile', $file);
151
        }
152
153 1
        return new Response($psrResponse, $this->factory);
154
    }
155
156 53
    protected function createPsrResponse(
157
        int $code = 200,
158
        string $reasonPhrase = ''
159
    ): PsrResponse {
160 53
        $response = $this->factory->response($code, $reasonPhrase);
161 53
        assert($response instanceof PsrResponse);
162
163 53
        return $response;
164
    }
165
166 37
    protected function createStream(mixed $body): PsrStream
167
    {
168 37
        $stream = $this->factory->stream($body);
169 36
        assert($stream instanceof PsrStream);
170
171 36
        return $stream;
172
    }
173
174 7
    protected function validateFile(string $file, bool $throwNotFound): void
175
    {
176 7
        if (!is_file($file)) {
177 2
            if ($throwNotFound) {
178 1
                throw new HttpNotFound();
179
            }
180
181 1
            throw new RuntimeException('File not found');
182
        }
183
    }
184
}
185