ResponseTransformer::createResponseFromContent()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 4
ccs 3
cts 3
cp 1
crap 1
rs 10
1
<?php
2
3
namespace MediaMonks\RestApi\Response;
4
5
use MediaMonks\RestApi\Model\ResponseModelFactory;
6
use MediaMonks\RestApi\Model\ResponseModelInterface;
7
use MediaMonks\RestApi\Request\Format;
8
use MediaMonks\RestApi\Serializer\SerializerInterface;
9
use Symfony\Component\HttpFoundation\Request;
10
use Symfony\Component\HttpFoundation\Response as SymfonyResponse;
11
use Symfony\Component\HttpFoundation\JsonResponse as SymfonyJsonResponse;
12
13
class ResponseTransformer implements ResponseTransformerInterface
14
{
15
16
    const WRAPPER_PADDING = 'padding';
17
18
    const WRAPPER_POST_MESSAGE = 'postMessage';
19
20
    const PARAMETER_CALLBACK = 'callback';
21
22
    const PARAMETER_WRAPPER = '_wrapper';
23
24
    /**
25
     * @var SerializerInterface
26
     */
27
    protected $serializer;
28
29
    /**
30
     * @var bool
31
     */
32
    protected $debug = false;
33
34
    /**
35
     * @var string
36
     */
37
    protected $postMessageOrigin;
38
39
    /**
40
     * @var ResponseModelFactory
41
     */
42
    protected $responseModelFactory;
43
44
    /**
45
     * @param SerializerInterface $serializer
46
     * @param ResponseModelFactory $responseModelFactory
47
     * @param array $options
48
     */
49 16
    public function __construct(
50
        SerializerInterface $serializer,
51
        ResponseModelFactory $responseModelFactory,
52
        $options = []
53
    ) {
54 16
        $this->serializer = $serializer;
55 16
        $this->responseModelFactory = $responseModelFactory;
56
57 16
        $this->setOptions($options);
58 16
    }
59
60
    /**
61
     * @param array $options
62
     */
63 16
    public function setOptions(array $options)
64
    {
65 16
        if (isset($options['debug'])) {
66 2
            $this->setDebug($options['debug']);
67 2
        }
68 16
        if (isset($options['post_message_origin'])) {
69 3
            $this->setPostMessageOrigin($options['post_message_origin']);
70 3
        }
71 16
    }
72
73
    /**
74
     * @return boolean
75
     */
76 5
    public function isDebug()
77
    {
78 5
        return $this->debug;
79
    }
80
81
    /**
82
     * @param boolean $debug
83
     *
84
     * @return ResponseTransformer
85
     */
86 2
    public function setDebug($debug)
87
    {
88 2
        $this->debug = $debug;
89
90 2
        return $this;
91
    }
92
93
    /**
94
     * @return string
95
     */
96 5
    public function getPostMessageOrigin()
97
    {
98 5
        return $this->postMessageOrigin;
99
    }
100
101
    /**
102
     * @param string $postMessageOrigin
103
     *
104
     * @return ResponseTransformer
105
     */
106 4
    public function setPostMessageOrigin($postMessageOrigin)
107
    {
108 4
        $this->postMessageOrigin = $postMessageOrigin;
109
110 4
        return $this;
111
    }
112
113
    /**
114
     * @param Request $request
115
     * @param SymfonyResponse $response
116
     *
117
     * @return SymfonyResponse
118
     */
119 4
    public function transformEarly(Request $request, SymfonyResponse $response)
120
    {
121 4
        if ($response instanceof ExtendedResponseInterface) {
122
            $responseModel = $response->getCustomContent();
123 4
        } else {
124 1
            $responseModel = $response->getContent();
125
        }
126 1
127 1
        if (!$responseModel instanceof ResponseModelInterface) {
128
            $responseModel = $this->responseModelFactory->createFromContent(
129 4
                $response
130 4
            );
131 4
        }
132 4
133 4
        $responseModel->setReturnStackTrace($this->isDebug());
134 4
        $response->setStatusCode($responseModel->getStatusCode());
135
        $this->forceStatusCodeHttpOK($request, $response, $responseModel);
136 4
        $response = $this->createSerializedResponse(
137
            $request,
138 4
            $response,
139
            $responseModel
140
        );
141
142
        return $response;
143
    }
144
145 4
    public function transformLate(Request $request, SymfonyResponse $response)
146
    {
147 4
        if ($request->getRequestFormat() === Format::FORMAT_JSON
148 4
            && $request->query->has(self::PARAMETER_CALLBACK)
149 4
            && $response instanceof JsonResponse
150 4
        ) {
151 2
            $this->wrapResponse($request, $response);
152 2
        }
153
154 4
        $this->forceEmptyResponseOnHttpNoContent($response);
155 4
    }
156
157
    /**
158
     * @param $data
159
     *
160
     * @return Response
161
     */
162 1
    public function createResponseFromContent($data)
163
    {
164 1
        return new Response(
165 1
            $this->responseModelFactory->createFromContent($data)
166 1
        );
167
    }
168
169
    /**
170
     * Check if we should put the status code in the output and force a 200 OK
171
     * in the header
172
     *
173
     * @param Request $request
174
     * @param SymfonyResponse $response
175
     * @param ResponseModelInterface $responseModel
176
     */
177 4
    protected function forceStatusCodeHttpOK(
178
        Request $request,
179
        SymfonyResponse $response,
180
        ResponseModelInterface $responseModel
181
    ) {
182 4
        if ($request->headers->has('X-Force-Status-Code-200')
183 1
            || ($request->getRequestFormat(
184 1
                ) == Format::FORMAT_JSON && $request->query->has(
185
                    self::PARAMETER_CALLBACK
186 1
                ))
187 4
        ) {
188 3
            $responseModel->setReturnStatusCode(true);
189 3
            $response->setStatusCode(Response::HTTP_OK);
190 3
            $response->headers->set('X-Status-Code', Response::HTTP_OK);
191 3
        }
192 4
    }
193
194
    /**
195
     * Make sure content is empty when the status code is "204 NoContent"
196
     *
197
     * @param SymfonyResponse $response
198
     */
199 4
    protected function forceEmptyResponseOnHttpNoContent(
200
        SymfonyResponse $response
201
    ) {
202 4
        if ($response->getStatusCode() === Response::HTTP_NO_CONTENT) {
203 1
            $response->setContent(null);
204 1
            if ($response instanceof ExtendedResponseInterface) {
205 1
                $response->setCustomContent(null);
206 4
            }
207
            $response->headers->remove('Content-Type');
208
        }
209
    }
210
211
    /**
212
     * @param Request $request
213
     * @param SymfonyResponse $response
214
     * @param ResponseModelInterface $responseModel
215 4
     *
216
     * @return SymfonyResponse
217
     */
218
    protected function createSerializedResponse(
219
        Request $request,
220
        SymfonyResponse $response,
221 4
        ResponseModelInterface $responseModel
222 4
    ) {
223 1
        try {
224
            $response = $this->serialize($request, $response, $responseModel);
225
        } catch (\Exception $e) {
226 1
            $response = new SymfonyJsonResponse(
227 1
                [
228 1
                    'error' => [
229
                        'code' => Error::CODE_GENERAL,
230 1
                        'message' => $e->getMessage(),
231
                    ],
232
                ]
233 4
            );
234
        }
235
236
        return $response;
237
    }
238
239
    /**
240
     * @param Request $request
241
     * @param SymfonyResponse $response
242
     * @param ResponseModelInterface $responseModel
243 4
     *
244
     * @return JsonResponse|SymfonyResponse
245
     */
246
    protected function serialize(
247
        Request $request,
248 4
        SymfonyResponse $response,
249 4
        ResponseModelInterface $responseModel
250 2
    ) {
251 2
        switch ($request->getRequestFormat()) {
252 2
            case Format::FORMAT_XML:
253 2
                $response->setContent(
254 2
                    $this->getSerializedContent($request, $responseModel)
255 2
                );
256 2
                break;
257 2
            default:
258 1
                $headers = $response->headers;
259 1
                $response = new JsonResponse(
260 1
                    $this->getSerializedContent($request, $responseModel),
261 1
                    $response->getStatusCode()
262 4
                );
263
                $response->headers = $headers; // some headers might mess up if we pass it to the JsonResponse
264 3
                break;
265
        }
266
267
        return $response;
268
    }
269
270
    /**
271
     * @param Request $request
272
     * @param ResponseModelInterface $responseModel
273 4
     *
274
     * @return mixed|string
275
     */
276
    protected function getSerializedContent(
277 4
        Request $request,
278 4
        ResponseModelInterface $responseModel
279 3
    ) {
280 3
        return $this->serializer->serialize(
281
            $responseModel->toArray(),
282
            $request->getRequestFormat()
283
        );
284
    }
285
286
    /**
287
     * @param Request $request
288
     * @param JsonResponse $response
289 2
     *
290
     * @throws \Exception
291 2
     */
292 2
    protected function wrapResponse(Request $request, JsonResponse $response)
293 1
    {
294 1
        switch ($request->query->get(self::PARAMETER_WRAPPER)) {
295 1
            case self::WRAPPER_POST_MESSAGE:
296 1
                $response->setContent(
297 1
                    sprintf(
298 1
                        $this->getPostMessageTemplate(),
299 1
                        $response->getContent(),
300 1
                        $this->getCallbackFromRequest($request),
301 1
                        $this->getPostMessageOrigin()
302 1
                    )
303 1
                )->headers->set('Content-Type', 'text/html');
304 1
                break;
305 1
            default:
306 1
                $response->setCallback(
307 2
                    $request->query->get(self::PARAMETER_CALLBACK)
308 2
                );
309
                break;
310
        }
311
    }
312
313
    /**
314
     * @param Request $request
315 1
     *
316
     * @return string
317 1
     */
318 1
    protected function getCallbackFromRequest(Request $request)
319
    {
320 1
        $response = new JsonResponse('');
321
        $response->setCallback($request->query->get(self::PARAMETER_CALLBACK));
322
323
        return $response->getCallback();
324
    }
325
326 1
    /**
327
     * @return string
328
     */
329
    protected function getPostMessageTemplate()
330
    {
331
        return <<<EOD
332
<html>
333
<body>
334
<script>
335
    try {
336
        var data = %s;
337
    }
338
    catch (error) {
339
        var data = {"error": {"code": "error.parse.post_message", "message": "Post message parse error"}};
340
    }
341
342
    top.postMessage(JSON.stringify({
343
        name: '%s',
344
        result: data
345
    }), '%s');
346 1
</script>
347
</body>
348
</html>
349
EOD;
350
    }
351
}
352