RequestTranslator::translate()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 2.0078

Importance

Changes 0
Metric Value
dl 0
loc 14
ccs 7
cts 8
cp 0.875
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 8
nc 2
nop 1
crap 2.0078
1
<?php
2
declare(strict_types = 1);
3
4
namespace Innmind\Rest\ServerBundle\Translator;
5
6
use Innmind\Http\{
7
    Message\ServerRequest as ServerRequestInterface,
8
    Message\ServerRequest\ServerRequest,
9
    Message\Method\Method,
10
    Message\Environment\Environment,
11
    Message\Environment as EnvironmentInterface,
12
    Message\Cookies\Cookies,
13
    Message\Cookies as CookiesInterface,
14
    Message\Query\Query,
15
    Message\Query as QueryInterface,
16
    Message\Query\Parameter as QueryParameterInterface,
17
    Message\Query\Parameter\Parameter as QueryParameter,
18
    Message\Form\Form,
19
    Message\Form as FormInterface,
20
    Message\Form\Parameter as FormParameterInterface,
21
    Message\Form\Parameter\Parameter as FormParameter,
22
    Message\Files\Files,
23
    Message\Files as FilesInterface,
24
    File\File,
25
    File as FileInterface,
26
    File\Status as StatusInterface,
27
    File\Status\Ok as OkStatus,
28
    File\Status\ExceedsFormMaxFileSize as ExceedsFormMaxFileSizeStatus,
29
    File\Status\ExceedsIniMaxFileSize as ExceedsIniMaxFileSizeStatus,
30
    File\Status\NoTemporaryDirectory as NoTemporaryDirectoryStatus,
31
    File\Status\NotUploaded as NotUploadedStatus,
32
    File\Status\PartiallyUploaded as PartiallyUploadedStatus,
33
    File\Status\StoppedByExtension as StoppedByExtensionStatus,
34
    File\Status\WriteFailed as WriteFailedStatus,
35
    ProtocolVersion\ProtocolVersion,
36
    Headers\Headers,
37
    Headers as HeadersInterface,
38
    Header as HeaderInterface,
39
    Factory\HeaderFactory as HeaderFactoryInterface
40
};
41
use Innmind\Filesystem\MediaType\MediaType;
42
use Innmind\Stream\Readable\Stream;
43
use Innmind\Url\Url;
44
use Innmind\Immutable\{
45
    Map,
46
    Str
47
};
48
use Symfony\Component\HttpFoundation\{
49
    Request,
50
    HeaderBag,
51
    ParameterBag,
52
    FileBag,
53
    ServerBag
54
};
55
56
final class RequestTranslator
57
{
58
    private $transformed;
59
    private $headerFactory;
60
61 6
    public function __construct(HeaderFactoryInterface $headerFactory)
62
    {
63 6
        $this->transformed = new Map(
64 6
            Request::class,
65 6
            ServerRequestInterface::class
66
        );
67 6
        $this->headerFactory = $headerFactory;
68 6
    }
69
70 4
    public function translate(Request $request): ServerRequestInterface
71
    {
72 4
        if ($this->transformed->contains($request)) {
73
            return $this->transformed->get($request);
74
        }
75
76 4
        $serverRequest = $this->doTranslation($request);
77 4
        $this->transformed = $this->transformed->put(
78 4
            $request,
79 4
            $serverRequest
80
        );
81
82 4
        return $serverRequest;
83
    }
84
85 4
    private function doTranslation(Request $request): ServerRequestInterface
86
    {
87 4
        $protocol = (new Str($request->server->get('SERVER_PROTOCOL')))->capture(
88 4
            '~HTTP/(?<major>\d)\.(?<minor>\d)~'
89
        );
90
91 4
        return new ServerRequest(
92 4
            Url::fromString(
93 4
                $request->getSchemeAndHttpHost().'/'.ltrim($request->getPathInfo(), '/')
94
            ),
95 4
            new Method($request->getMethod()),
96 4
            new ProtocolVersion(
97 4
                (int) (string) $protocol['major'],
98 4
                (int) (string) $protocol['minor']
99
            ),
100 4
            $this->translateHeaders($request->headers),
101 4
            new Stream($request->getContent(true)),
102 4
            $this->translateEnvironment($request->server),
103 4
            $this->translateCookies($request->cookies),
104 4
            $this->translateQuery($request->query),
105 4
            $this->translateForm($request->request),
106 4
            $this->translateFiles($request->files)
107
        );
108
    }
109
110 4
    private function translateHeaders(HeaderBag $headerBag): HeadersInterface
111
    {
112 4
        $map = new Map('string', HeaderInterface::class);
113
114 4
        foreach ($headerBag as $name => $value) {
115 2
            $map = $map->put(
116 2
                $name,
117 2
                $this->headerFactory->make(
118 2
                    new Str($name),
119 2
                    new Str(implode(', ', $value))
120
                )
121
            );
122
        }
123
124 4
        return new Headers($map);
125
    }
126
127 4
    private function translateEnvironment(ServerBag $server): EnvironmentInterface
128
    {
129 4
        $map = new Map('string', 'scalar');
130
131 4
        foreach ($server as $key => $value) {
132 4
            if (!is_scalar($value)) {
133
                continue;
134
            }
135
136 4
            $map = $map->put($key, $value);
137
        }
138
139 4
        return new Environment($map);
140
    }
141
142 4
    private function translateCookies(ParameterBag $cookies): CookiesInterface
143
    {
144 4
        $map = new Map('string', 'scalar');
145
146 4
        foreach ($cookies as $key => $value) {
147 2
            $map = $map->put($key, $value);
148
        }
149
150 4
        return new Cookies($map);
151
    }
152
153 4
    private function translateQuery(ParameterBag $query): QueryInterface
154
    {
155 4
        $map = new Map('string', QueryParameterInterface::class);
156
157 4
        foreach ($query as $key => $value) {
158 2
            $map = $map->put(
159 2
                $key,
160 2
                new QueryParameter($key, $value)
161
            );
162
        }
163
164 4
        return new Query($map);
165
    }
166
167 4
    private function translateForm(ParameterBag $form): FormInterface
168
    {
169 4
        $map = new Map('scalar', FormParameterInterface::class);
170
171 4
        foreach ($form as $key => $value) {
172 2
            $map = $map->put(
173 2
                $key,
174 2
                $this->buildFormParameter($key, $value)
175
            );
176
        }
177
178 4
        return new Form($map);
179
    }
180
181 2
    private function buildFormParameter($name, $value): FormParameterInterface
182
    {
183 2
        if (!is_array($value)) {
184 2
            return new FormParameter((string) $name, $value);
185
        }
186
187
        $map = new Map('scalar', FormParameterInterface::class);
188
189
        foreach ($value as $key => $sub) {
190
            $map = $map->put(
191
                $key,
192
                $this->buildFormParameter($key, $sub)
193
            );
194
        }
195
196
        return new FormParameter((string) $name, $map);
197
    }
198
199 4
    private function translateFiles(FileBag $files): FilesInterface
200
    {
201 4
        $map = new Map('string', FileInterface::class);
202
203 4
        foreach ($files as $name => $file) {
204 2
            $map = $map->put(
205 2
                $name,
206 2
                new File(
207 2
                    $file->getClientOriginalName(),
208 2
                    new Stream(
209 2
                        fopen($file->getPathname(), 'r')
210
                    ),
211 2
                    $this->buildFileStatus($file->getError()),
212 2
                    MediaType::fromString((string) $file->getClientMimeType())
213
                )
214
            );
215
        }
216
217 4
        return new Files($map);
218
    }
219
220 2
    private function buildFileStatus(int $status): StatusInterface
221
    {
222
        switch ($status) {
223 2
            case UPLOAD_ERR_FORM_SIZE:
224
                return new ExceedsFormMaxFileSizeStatus;
225 2
            case UPLOAD_ERR_INI_SIZE:
226
                return new ExceedsIniMaxFileSizeStatus;
227 2
            case UPLOAD_ERR_NO_TMP_DIR:
228
                return new NoTemporaryDirectoryStatus;
229 2
            case UPLOAD_ERR_NO_FILE:
230
                return new NotUploadedStatus;
231 2
            case UPLOAD_ERR_OK:
232 2
                return new OkStatus;
233
            case UPLOAD_ERR_PARTIAL:
234
                return new PartiallyUploadedStatus;
235
            case UPLOAD_ERR_EXTENSION:
236
                return new StoppedByExtensionStatus;
237
            case UPLOAD_ERR_CANT_WRITE:
238
                return new WriteFailedStatus;
239
        }
240
    }
241
}
242