Completed
Push — master ( 61a9ce...9b36d9 )
by
unknown
03:37
created

ResponseTransformer::setDebug()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

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